cogs||bzoj1036 树的统计count
题目大意:模板题。
思路:模板题。

#include<iostream>
#include<cstdio>
#define maxnode 30001
#define mid (l+r)/2
#define inf 2100000000LL
using namespace std;
struct use{
int fa,top,siz,son,dep,tid;
}tree[maxnode]={0};
struct seg{
int maxn,sum;
}t[maxnode*4]={0};
int point[maxnode*2]={0},next[maxnode*2]={0},en[maxnode*2],tot=0,tt[maxnode],wi[maxnode];
char ch[10];
bool visit[maxnode]={false};
void add(int st,int enn)
{
++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;
++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;
}
void findc(int u,int fa,int depth)
{
int i,j,maxsiz=0;
visit[u]=true;tree[u].siz=1;
tree[u].fa=fa;tree[u].dep=depth;
for (i=point[u];i;i=next[i])
if (!visit[en[i]])
{
j=en[i];findc(j,u,depth+1);
tree[u].siz+=tree[j].siz;
if (tree[j].siz>maxsiz)
{
maxsiz=tree[j].siz;
tree[u].son=j;
}
}
}
void connc(int u,int top)
{
int i,j;
visit[u]=false;tree[u].top=top;
tree[u].tid=++tot;tt[tot]=u;
if (tree[u].son)
connc(tree[u].son,top);
for (i=point[u];i;i=next[i])
if (visit[en[i]])
{
j=en[i];connc(j,j);
}
}
void updata(int i)
{
t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn);
t[i].sum=t[i*2].sum+t[i*2+1].sum;
}
void build(int i,int l,int r)
{
if (l==r)
{
t[i].maxn=t[i].sum=wi[tt[l]];return;
}
build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);
}
void change(int i,int l,int r,int x,int y)
{
if (l==r)
{
t[i].maxn=t[i].sum=y;return;
}
if (x<=mid) change(i*2,l,mid,x,y);
else change(i*2+1,mid+1,r,x,y);
updata(i);
}
int tmax(int i,int l,int r,int ll,int rr)
{
int maxn;
if (ll<=l&&r<=rr) return t[i].maxn;
maxn=-inf;
if (ll<=mid) maxn=max(maxn,tmax(i*2,l,mid,ll,rr));
if (rr>mid) maxn=max(maxn,tmax(i*2+1,mid+1,r,ll,rr));
return maxn;
}
int tsum(int i,int l,int r,int ll,int rr)
{
int sum=0;
if (ll<=l&&r<=rr) return t[i].sum;
if (ll<=mid) sum+=tsum(i*2,l,mid,ll,rr);
if (rr>mid) sum+=tsum(i*2+1,mid+1,r,ll,rr);
return sum;
}
int qmax(int x,int y)
{
int maxn;
maxn=-inf;
while(tree[x].top!=tree[y].top)
{
if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y);
maxn=max(maxn,tmax(1,1,tot,tree[tree[x].top].tid,tree[x].tid));
x=tree[tree[x].top].fa;
}
if (tree[x].dep<tree[y].dep) swap(x,y);
maxn=max(maxn,tmax(1,1,tot,tree[y].tid,tree[x].tid));
return maxn;
}
int qsum(int x,int y)
{
int sum=0;
while(tree[x].top!=tree[y].top)
{
if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y);
sum+=tsum(1,1,tot,tree[tree[x].top].tid,tree[x].tid);
x=tree[tree[x].top].fa;
}
if (tree[x].dep<tree[y].dep) swap(x,y);
sum+=tsum(1,1,tot,tree[y].tid,tree[x].tid);
return sum;
}
int main()
{
freopen("bzoj_1036.in","r",stdin);
freopen("bzoj_1036.out","w",stdout);
int i,j,n,m,a,b,ans;
scanf("%d",&n);
for (i=1;i<n;++i)
{
scanf("%d%d",&a,&b);
add(a,b);
}
findc(1,0,1);
tot=0;connc(1,1);
for (i=1;i<=n;++i) scanf("%d",&wi[i]);
build(1,1,tot);
scanf("%d",&m);
for (i=1;i<=m;++i)
{
scanf("%*c%s",&ch);scanf("%d%d",&a,&b);
if (ch[0]=='C') change(1,1,tot,tree[a].tid,b);
else
{
if (ch[1]=='M') ans=qmax(a,b);
else ans=qsum(a,b);
printf("%d\n",ans);
}
}
fclose(stdin);
fclose(stdout);
}
cogs 树的维护
题目大意:模板题+区间取反。
思路:取反的时候是纯线段树操作,有很多细节:insert、updata和ask的时候都要考虑delta的取值。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxnode 10001
#define mid (l+r)/2
#define inf 2100000000
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2],va[maxnode*2],bi[maxnode*2],tt[maxnode]={0},wi[maxnode];
char ch[10];
struct use{
int maxn,minn,delta,sig;
}t[maxnode*4];
void updata(int i)
{
t[i].maxn=max((t[i].sig==t[i*2].sig ? t[i*2].maxn : -t[i*2].minn),(t[i].sig==t[i*2+1].sig ? t[i*2+1].maxn : -t[i*2+1].minn));
t[i].minn=min((t[i].sig==t[i*2].sig ? t[i*2].minn : -t[i*2].maxn),(t[i].sig==t[i*2+1].sig ? t[i*2+1].minn : -t[i*2+1].maxn));
}
void build(int i,int l,int r)
{
if (l==r)
{
t[i].maxn=t[i].minn=wi[tt[l]];
t[i].delta=t[i].sig=0;return;
}
build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);
}
void paint(int i)
{
t[i].sig=1-t[i].sig;t[i].delta=1-t[i].delta;
}
void pushdown(int i)
{
if (t[i].delta)
{
paint(i*2);paint(i*2+1);
t[i].delta=0;
}
}
void tchange(int i,int l,int r,int x,int y)
{
if (l==r)
{
if (t[i].sig) t[i].maxn=t[i].minn=-y;
else t[i].maxn=t[i].minn=y;
return;
}
pushdown(i);
if (x<=mid) tchange(i*2,l,mid,x,y);
else tchange(i*2+1,mid+1,r,x,y);
updata(i);
}
void tneg(int i,int l,int r,int ll,int rr)
{
if (ll<=l&&r<=rr)
{
paint(i);return;
}
pushdown(i);
if (ll<=mid) tneg(i*2,l,mid,ll,rr);
if (rr>mid) tneg(i*2+1,mid+1,r,ll,rr);
updata(i);
}
int tmax(int i,int l,int r,int ll,int rr)
{
int maxn;
if (ll<=l&&r<=rr)
{
if (t[i].sig) return -t[i].minn;
else return t[i].maxn;
}
maxn=-inf;pushdown(i);
if (ll<=mid) maxn=max(maxn,tmax(i*2,l,mid,ll,rr));
if (rr>mid) maxn=max(maxn,tmax(i*2+1,mid+1,r,ll,rr));
return maxn;
}
struct lp{
int fa[maxnode],son[maxnode],dep[maxnode],top[maxnode],siz[maxnode],tid[maxnode],edge[maxnode],tot;
bool visit[maxnode];
void add(int st,int enn,int vaa,int i)
{
++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;va[tot]=vaa;bi[tot]=i;
++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;va[tot]=vaa;bi[tot]=i;
}
void dfs1(int u,int ff,int depth,int vaa,int ii)
{
int i,j,maxsiz=0;
visit[u]=true;fa[u]=ff;dep[u]=depth;
son[u]=0;siz[u]=1;wi[u]=vaa;edge[ii]=u;
for (i=point[u];i;i=next[i])
if (!visit[j=en[i]])
{
dfs1(j,u,depth+1,va[i],bi[i]);
siz[u]+=siz[j];
if (siz[j]>maxsiz)
{
maxsiz=siz[j];son[u]=j;
}
}
}
void dfs2(int u,int anc)
{
int i,j;
visit[u]=false;top[u]=anc;
tid[u]=++tot;tt[tot]=u;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
if (visit[j=en[i]]) dfs2(j,j);
}
void change(int a,int b)
{
a=tid[edge[a]];
tchange(1,1,tot,a,b);
}
void neg(int a,int b)
{
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
tneg(1,1,tot,tid[top[a]],tid[a]);
a=fa[top[a]];
}
if (dep[a]>dep[b]) swap(a,b);
if (a!=b) tneg(1,1,tot,tid[son[a]],tid[b]);
}
void qmax(int a,int b)
{
int maxn;
maxn=-inf;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
maxn=max(maxn,tmax(1,1,tot,tid[top[a]],tid[a]));
a=fa[top[a]];
}
if (dep[a]>dep[b]) swap(a,b);
if (a!=b) maxn=max(maxn,tmax(1,1,tot,tid[son[a]],tid[b]));
printf("%d\n",maxn);
}
}tree;
int main()
{
freopen("maintaintree.in","r",stdin);
freopen("maintaintree.out","w",stdout);
int n,i,j,a,b,c;
scanf("%d",&n);tree.tot=0;
memset(tree.visit,false,sizeof(tree.visit));
for (i=1;i<n;++i)
{
scanf("%d%d%d",&a,&b,&c);
tree.add(a,b,c,i);
}
tree.dfs1(1,0,1,0,0);
tree.tot=0;tree.dfs2(1,1);
build(1,1,tree.tot);
while(scanf("%*c%s",&ch)==1)
{
if (ch[0]=='D') break;
scanf("%d%d",&a,&b);
if (ch[0]=='C') tree.change(a,b);
if (ch[0]=='N') tree.neg(a,b);
if (ch[0]=='Q') tree.qmax(a,b);
}
fclose(stdin);
fclose(stdout);
}
bzoj3083 遥远的国度
题目大意:换父亲、改点权、子树最小值。
思路:换父亲是三种情况的分类讨论:我们并不是真的换父亲、重新建树。当前根root,子树的根节点x。1)如果root=x,就查询整棵树;2)如果当lca(root,x)!=x,就查询x的子树;3)如果当lca(root,x)=x,就查询x的儿子中离root最近的那个儿子在整棵树中的补集。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 100001
#define inf 0x7fffffff
using namespace std;
struct use{
int delta,minn;
}t[maxnode*4]={0};
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},tot=0,id[maxnode]={0};
void updata(int i)
{
t[i].minn=min(t[i*2].minn,t[i*2+1].minn);
}
void pushdown(int i)
{
if (t[i].delta)
{
t[i*2].minn=t[i*2].delta=t[i].delta;
t[i*2+1].minn=t[i*2+1].delta=t[i].delta;
t[i].delta=0;
}
}
void build(int i,int l,int r)
{
int mid;
if (l==r)
{
t[i].delta=0;t[i].minn=fy[id[l]];return;
}
mid=(l+r)/2;
build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);
}
void tch(int i,int l,int r,int ll,int rr,int v)
{
int mid;
if (ll<=l&&r<=rr)
{
t[i].delta=t[i].minn=v;return;
}
mid=(l+r)/2;
pushdown(i);
if (ll<=mid) tch(i*2,l,mid,ll,rr,v);
if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,v);
updata(i);
}
int task(int i,int l,int r,int ll,int rr)
{
int mid,ans;
if (ll<=l&&r<=rr) return t[i].minn;
mid=(l+r)/2;ans=inf;pushdown(i);
if (ll<=mid) ans=min(ans,task(i*2,l,mid,ll,rr));
if (rr>mid) ans=min(ans,task(i*2+1,mid+1,r,ll,rr));
return ans;
}
struct lp{
int fa[maxnode][20],son[maxnode],dep[maxnode],top[maxnode],siz[maxnode],tid[maxnode],ri[maxnode];
bool visit[maxnode];
void add(int st,int enn)
{
++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;
++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;
}
void dfs1(int u,int ff,int depth)
{
int i,j,maxsiz=0;
visit[u]=true;fa[u][0]=ff;dep[u]=depth;
son[u]=0;siz[u]=1;
for (i=1;i<=18;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
for (i=point[u];i;i=next[i])
{
if (!visit[j=en[i]])
{
dfs1(j,u,depth+1);
siz[u]+=siz[j];
if (siz[j]>maxsiz)
{
maxsiz=siz[j];son[u]=j;
}
}
}
}
void dfs2(int u,int anc)
{
int i,j;
visit[u]=false;top[u]=anc;
tid[u]=++tot;id[tot]=u;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
{
if (visit[j=en[i]]) dfs2(j,j);
}
ri[u]=tot;
}
int lca(int a,int b)
{
int i,j;
if (dep[a]>dep[b]) swap(a,b);
for (i=18;i>=0;--i)
if (dep[a]<=dep[fa[b][i]]) b=fa[b][i];
if (a==b) return a;
for (i=18;i>=0;--i)
{
if (fa[a][i]!=fa[b][i])
{
a=fa[a][i];b=fa[b][i];
}
}
return fa[a][0];
}
void change(int a,int b,int v)
{
int i,j;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
tch(1,1,tot,tid[top[a]],tid[a],v);
a=fa[top[a]][0];
}
if (dep[a]>dep[b]) swap(a,b);
tch(1,1,tot,tid[a],tid[b],v);
}
int ask(int a,int root)
{
int ans,ll,i,j;
if (a==root) return task(1,1,tot,1,tot);
ll=lca(a,root);
if (ll!=a) return task(1,1,tot,tid[a],ri[a]);
else
{
ans=inf;j=root;
for (i=18;i>=0;--i)
if (dep[fa[j][i]]>dep[a]) j=fa[j][i];
ans=min((tid[j]>1 ? task(1,1,tot,1,tid[j]-1) : inf),(ri[j]<tot ? task(1,1,tot,ri[j]+1,tot) : inf));
return ans;
}
}
}tree;
int main()
{
int u,v,n,m,i,j,opt,root,p1,p2,ans;
scanf("%d%d",&n,&m);
for (i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
tree.add(u,v);
}
for (i=1;i<=n;++i) scanf("%d",&fy[i]);
scanf("%d",&root);tot=0;
memset(tree.visit,false,sizeof(tree.visit));
tree.dfs1(root,0,1);
tree.dfs2(root,root);
build(1,1,tot);
for (i=1;i<=m;++i)
{
scanf("%d",&opt);
if (opt==1) scanf("%d",&root);
if (opt==2)
{
scanf("%d%d%d",&p1,&p2,&v);
tree.change(p1,p2,v);
}
if (opt==3)
{
scanf("%d",&p1);
ans=tree.ask(p1,root);
printf("%d\n",ans);
}
}
}
bzoj2243 染色
题目大意:区间修改、区间不同子段的个数。
思路:线段树上的操作。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 100001
using namespace std;
struct use{
int lc,rc,sum,delta;
}t[maxnode*4]={0};
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},id[maxnode]={0},tot=0,fy[maxnode]={0};
void updata(int i)
{
t[i].lc=t[i*2].lc;t[i].rc=t[i*2+1].rc;
t[i].sum=t[i*2].sum+t[i*2+1].sum;
if (t[i*2].rc==t[i*2+1].lc) --t[i].sum;
}
void pushdown(int i)
{
if (t[i].delta>=0)
{
t[i*2].lc=t[i*2].rc=t[i*2].delta=t[i].delta;t[i*2].sum=1;
t[i*2+1].lc=t[i*2+1].rc=t[i*2+1].delta=t[i].delta;t[i*2+1].sum=1;
t[i].delta=-1;
}
}
void build(int i,int l,int r)
{
int mid;
if (l==r)
{
t[i].lc=t[i].rc=fy[id[l]];t[i].sum=1;t[i].delta=-1;return;
}
mid=(l+r)/2;
build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);t[i].delta=-1;
}
void tch(int i,int l,int r,int ll,int rr,int v)
{
int mid;
if (ll<=l&&r<=rr)
{
t[i].lc=t[i].rc=t[i].delta=v;t[i].sum=1;return;
}
mid=(l+r)/2;pushdown(i);
if (ll<=mid) tch(i*2,l,mid,ll,rr,v);
if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,v);
updata(i);
}
struct use task(int i,int l,int r,int ll,int rr)
{
int mid,sum=0;
bool u1=false,u2=false;
struct use n1,n2,ans;
if (ll<=l&&r<=rr) return t[i];
mid=(l+r)/2;pushdown(i);
if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);}
if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);}
if (u1) ans.lc=n1.lc;
else ans.lc=n2.lc;
if (u2) ans.rc=n2.rc;
else ans.rc=n1.rc;
ans.sum=(u1 ? n1.sum : 0)+(u2 ? n2.sum : 0);
if (u1&&u2&&n1.rc==n2.lc) --ans.sum;
return ans;
}
struct lp{
int fa[maxnode],dep[maxnode],son[maxnode],siz[maxnode],top[maxnode],tid[maxnode];
bool visit[maxnode];
void add(int u,int v)
{
++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
}
void dfs1(int u,int ff,int depth)
{
int i,j,maxsiz=0;
fa[u]=ff;dep[u]=depth;son[u]=0;
visit[u]=true;siz[u]=1;
for (i=point[u];i;i=next[i])
{
if (!visit[j=en[i]])
{
dfs1(j,u,depth+1);
siz[u]+=siz[j];
if (siz[j]>maxsiz)
{
maxsiz=siz[j];son[u]=j;
}
}
}
}
void dfs2(int u,int anc)
{
int i,j;
tid[u]=++tot;top[u]=anc;
visit[u]=false;id[tot]=u;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
{
if (visit[j=en[i]]) dfs2(j,j);
}
}
void change(int a,int b,int v)
{
int i;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
tch(1,1,tot,tid[top[a]],tid[a],v);
a=fa[top[a]];
}
if (dep[a]>dep[b]) swap(a,b);
tch(1,1,tot,tid[a],tid[b],v);
}
int ask(int a,int b)
{
int ans=0,co[2],kk=0;
struct use i;
co[0]=co[1]=-1;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]])
{
swap(a,b);kk^=1;
}
i=task(1,1,tot,tid[top[a]],tid[a]);
ans+=i.sum;
if (co[kk]==i.rc) --ans;
co[kk]=i.lc;
a=fa[top[a]];
}
if (dep[a]>dep[b])
{
swap(a,b);kk^=1;
}
i=task(1,1,tot,tid[a],tid[b]);
ans+=i.sum;
if (co[kk]==i.lc) --ans;
co[kk]=i.rc;
if (co[kk]==co[kk^1]) --ans;
return ans;
}
}tree;
int main()
{
int n,m,i,j,u,v,t;
char ch;
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i) scanf("%d",&fy[i]);
for (i=1;i<n;++i)
{
scanf("%d%d",&u,&v);tree.add(u,v);
}
memset(tree.visit,false,sizeof(tree.visit));
tree.dfs1(1,0,1);tot=0;
tree.dfs2(1,1);build(1,1,tot);
for (i=1;i<=m;++i)
{
while(scanf("%c",&ch)==1)
{
if (ch=='C'||ch=='Q') break;
}
if (ch=='C')
{
scanf("%d%d%d",&u,&v,&t);
tree.change(u,v,t);
}
else
{
scanf("%d%d",&u,&v);
printf("%d\n",tree.ask(u,v));
}
}
}
codevs3305&&3306 水果姐逛水果街系列
题目大意:查询树上从a到b的路径中后面减前面的最大差值(+单点修改)。
思路:链剖+线段树的操作,稍复杂一点,分类讨论。有点像上一题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 200001
#define inf 2100000000
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},id[maxnode]={0},tot=0;
struct use{
int maxn,minn,mac,mic;
}t[maxnode*4];
void updata(int i)
{
t[i].mac=max(t[i*2].mac,max(t[i*2+1].mac,t[i*2+1].maxn-t[i*2].minn));
t[i].mic=max(t[i*2].mic,max(t[i*2+1].mic,t[i*2].maxn-t[i*2+1].minn));
t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn);
t[i].minn=min(t[i*2].minn,t[i*2+1].minn);
}
void build(int i,int l,int r)
{
int mid;
if (l==r)
{
t[i].maxn=t[i].minn=fy[id[l]];t[i].mac=t[i].mic=0;return;
}
mid=(l+r)/2;
build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);
}
void tch(int i,int l,int r,int x,int y)
{
int mid;
if (l==r)
{
t[i].maxn=t[i].minn=y;t[i].mac=t[i].mic=0;return;
}
mid=(l+r)/2;
if (x<=mid) tch(i*2,l,mid,x,y);
else tch(i*2+1,mid+1,r,x,y);
updata(i);
}
struct use task(int i,int l,int r,int ll,int rr)
{
int mid;
struct use n1,n2,ans;
bool u1=false,u2=false;
if (ll<=l&&r<=rr) return t[i];
mid=(l+r)/2;
if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);}
if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);}
ans.maxn=0;ans.minn=inf;ans.mac=ans.mic=0;
if (u1)
{
ans.maxn=max(ans.maxn,n1.maxn);
ans.minn=min(ans.minn,n1.minn);
ans.mac=max(ans.mac,n1.mac);
ans.mic=max(ans.mic,n1.mic);
}
if (u2)
{
ans.maxn=max(ans.maxn,n2.maxn);
ans.minn=min(ans.minn,n2.minn);
ans.mac=max(ans.mac,n2.mac);
ans.mic=max(ans.mic,n2.mic);
}
if (u1&&u2)
{
ans.mac=max(ans.mac,n2.maxn-n1.minn);
ans.mic=max(ans.mic,n1.maxn-n2.minn);
}
return ans;
}
struct lp{
int fa[maxnode],dep[maxnode],top[maxnode],tid[maxnode],son[maxnode],siz[maxnode];
bool visit[maxnode];
void add(int u,int v)
{
++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
}
void dfs1(int u,int ff,int depth)
{
int i,j,maxsiz=0;
fa[u]=ff;dep[u]=depth;visit[u]=true;
son[u]=0;siz[u]=1;
for (i=point[u];i;i=next[i])
{
if (!visit[j=en[i]])
{
dfs1(j,u,depth+1);
siz[u]+=siz[j];
if (siz[j]>maxsiz)
{
maxsiz=siz[j];son[u]=j;
}
}
}
}
void dfs2(int u,int anc)
{
int i,j;
top[u]=anc;tid[u]=++tot;
id[tot]=u;visit[u]=false;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
if (visit[j=en[i]]) dfs2(j,j);
}
int ask(int a,int b)
{
int j,ans=0,kk=0;
struct use mo[2],i;
mo[0].maxn=mo[1].maxn=0;mo[0].minn=mo[1].minn=inf;
mo[0].mac=mo[1].mac=mo[0].mic=mo[1].mic=0;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]])
{
swap(a,b);kk^=1;
}
i=task(1,1,tot,tid[top[a]],tid[a]);
if (!kk)
{
ans=max(ans,max(i.mic,i.maxn-mo[kk].minn));
mo[kk].minn=min(mo[kk].minn,i.minn);
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
}
else
{
ans=max(ans,max(i.mac,mo[kk].maxn-i.minn));
mo[kk].minn=min(mo[kk].minn,i.minn);
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
}
a=fa[top[a]];
}
if (dep[a]>dep[b])
{
swap(a,b);kk^=1;
}
i=task(1,1,tot,tid[a],tid[b]);
if (!kk)
{
ans=max(ans,max(i.mac,i.maxn-mo[kk].minn));
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
mo[kk].minn=min(mo[kk].minn,i.minn);
ans=max(ans,mo[kk^1].maxn-mo[kk].minn);
}
else
{
ans=max(ans,max(i.mic,mo[kk].maxn-i.minn));
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
mo[kk].minn=min(mo[kk].minn,i.minn);
ans=max(ans,mo[kk].maxn-mo[kk^1].minn);
}
return ans;
}
}tree;
int main()
{
int n,m,i,j,x,y,u,v;
scanf("%d",&n);
for (i=1;i<=n;++i) scanf("%d",&fy[i]);
for (i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
tree.add(u,v);
}
memset(tree.visit,false,sizeof(tree.visit));
tree.dfs1(1,0,1);tot=0;
tree.dfs2(1,1);scanf("%d",&m);
build(1,1,tot);
for (i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
printf("%d\n",tree.ask(x,y));
}
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 200001
#define inf 2100000000
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},id[maxnode]={0},tot=0;
struct use{
int maxn,minn,mac,mic;
}t[maxnode*4];
void updata(int i)
{
t[i].mac=max(t[i*2].mac,max(t[i*2+1].mac,t[i*2+1].maxn-t[i*2].minn));
t[i].mic=max(t[i*2].mic,max(t[i*2+1].mic,t[i*2].maxn-t[i*2+1].minn));
t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn);
t[i].minn=min(t[i*2].minn,t[i*2+1].minn);
}
void build(int i,int l,int r)
{
int mid;
if (l==r)
{
t[i].maxn=t[i].minn=fy[id[l]];t[i].mac=t[i].mic=0;return;
}
mid=(l+r)/2;
build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);
}
void tch(int i,int l,int r,int x,int y)
{
int mid;
if (l==r)
{
t[i].maxn=t[i].minn=y;t[i].mac=t[i].mic=0;return;
}
mid=(l+r)/2;
if (x<=mid) tch(i*2,l,mid,x,y);
else tch(i*2+1,mid+1,r,x,y);
updata(i);
}
struct use task(int i,int l,int r,int ll,int rr)
{
int mid;
struct use n1,n2,ans;
bool u1=false,u2=false;
if (ll<=l&&r<=rr) return t[i];
mid=(l+r)/2;
if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);}
if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);}
ans.maxn=0;ans.minn=inf;ans.mac=ans.mic=0;
if (u1)
{
ans.maxn=max(ans.maxn,n1.maxn);
ans.minn=min(ans.minn,n1.minn);
ans.mac=max(ans.mac,n1.mac);
ans.mic=max(ans.mic,n1.mic);
}
if (u2)
{
ans.maxn=max(ans.maxn,n2.maxn);
ans.minn=min(ans.minn,n2.minn);
ans.mac=max(ans.mac,n2.mac);
ans.mic=max(ans.mic,n2.mic);
}
if (u1&&u2)
{
ans.mac=max(ans.mac,n2.maxn-n1.minn);
ans.mic=max(ans.mic,n1.maxn-n2.minn);
}
return ans;
}
struct lp{
int fa[maxnode],dep[maxnode],top[maxnode],tid[maxnode],son[maxnode],siz[maxnode];
bool visit[maxnode];
void add(int u,int v)
{
++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
}
void dfs1(int u,int ff,int depth)
{
int i,j,maxsiz=0;
fa[u]=ff;dep[u]=depth;visit[u]=true;
son[u]=0;siz[u]=1;
for (i=point[u];i;i=next[i])
{
if (!visit[j=en[i]])
{
dfs1(j,u,depth+1);
siz[u]+=siz[j];
if (siz[j]>maxsiz)
{
maxsiz=siz[j];son[u]=j;
}
}
}
}
void dfs2(int u,int anc)
{
int i,j;
top[u]=anc;tid[u]=++tot;
id[tot]=u;visit[u]=false;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
if (visit[j=en[i]]) dfs2(j,j);
}
int ask(int a,int b)
{
int j,ans=0,kk=0;
struct use mo[2],i;
mo[0].maxn=mo[1].maxn=0;mo[0].minn=mo[1].minn=inf;
mo[0].mac=mo[1].mac=mo[0].mic=mo[1].mic=0;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]])
{
swap(a,b);kk^=1;
}
i=task(1,1,tot,tid[top[a]],tid[a]);
if (!kk)
{
ans=max(ans,max(i.mic,i.maxn-mo[kk].minn));
mo[kk].minn=min(mo[kk].minn,i.minn);
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
}
else
{
ans=max(ans,max(i.mac,mo[kk].maxn-i.minn));
mo[kk].minn=min(mo[kk].minn,i.minn);
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
}
a=fa[top[a]];
}
if (dep[a]>dep[b])
{
swap(a,b);kk^=1;
}
i=task(1,1,tot,tid[a],tid[b]);
if (!kk)
{
ans=max(ans,max(i.mac,i.maxn-mo[kk].minn));
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
mo[kk].minn=min(mo[kk].minn,i.minn);
ans=max(ans,mo[kk^1].maxn-mo[kk].minn);
}
else
{
ans=max(ans,max(i.mic,mo[kk].maxn-i.minn));
mo[kk].maxn=max(mo[kk].maxn,i.maxn);
mo[kk].minn=min(mo[kk].minn,i.minn);
ans=max(ans,mo[kk].maxn-mo[kk^1].minn);
}
return ans;
}
}tree;
int main()
{
int n,m,i,j,x,y,u,v;
scanf("%d",&n);
for (i=1;i<=n;++i) scanf("%d",&fy[i]);
for (i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
tree.add(u,v);
}
memset(tree.visit,false,sizeof(tree.visit));
tree.dfs1(1,0,1);tot=0;
tree.dfs2(1,1);scanf("%d",&m);
build(1,1,tot);
for (i=1;i<=m;++i)
{
scanf("%d%d%d",&j,&x,&y);
if (j==0) tch(1,1,tot,tree.tid[x],y);
else printf("%d\n",tree.ask(x,y));
}
}
moe
题目大意:给定一个图,有两种操作:1)删掉一条边;2)求图中桥的数量。
思路:对于删边类的问题,大多是倒着来做。删掉所有边后,可能仍然是个图,我们dfs出一棵树,这些边都是当前的桥,把图中的边一条一条加上,它连接的两点间的边都不是桥了,维护的过程就是链剖+线段树区间修改和查询。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxnode 100005
using namespace std;
struct use{
int st,en,flag;
}edge[maxnode]={0};
struct uu{
int num,delta;
}t[maxnode*4]={0};
int tot=0,ask[maxnode][4]={0},point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},n,tot1=0;
bool visit[maxnode]={false};
map <int,int> dui[maxnode];
void add(int u,int v)
{
edge[++tot].st=u;edge[tot].en=v;edge[tot].flag=0;
dui[u][v]=dui[v][u]=tot;
next[tot*2-1]=point[u];point[u]=tot*2-1;en[tot*2-1]=v;
next[tot*2]=point[v];point[v]=tot*2;en[tot*2]=u;
}
void updata(int i){t[i].num=t[i*2].num+t[i*2+1].num;}
void pushdown(int i,int l,int r)
{
int mid;
if (t[i].delta)
{
t[i*2].delta=t[i*2+1].delta=1;
t[i*2].num=t[i*2+1].num=0;
t[i].delta=0;
}
}
void build(int i,int l,int r)
{
int mid;
if (l==r){t[i].num=1;t[i].delta=0;return;}
mid=(l+r)/2;build(i*2,l,mid);build(i*2+1,mid+1,r);
updata(i);
}
int task(int i,int l,int r,int ll,int rr)
{
int mid,ans=0;
if (ll<=l&&r<=rr) return t[i].num;
mid=(l+r)/2;pushdown(i,l,r);
if (ll<=mid) ans+=task(i*2,l,mid,ll,rr);
if (rr>mid) ans+=task(i*2+1,mid+1,r,ll,rr);
return ans;
}
void tch(int i,int l,int r,int ll,int rr)
{
int mid;
if (ll<=l&&r<=rr)
{
t[i].num=0;t[i].delta=1;return;
} mid=(l+r)/2;pushdown(i,l,r);
if (ll<=mid) tch(i*2,l,mid,ll,rr);
if (rr>mid) tch(i*2+1,mid+1,r,ll,rr);
updata(i);
}
struct lp{
int fa[maxnode],tid[maxnode],son[maxnode],siz[maxnode],top[maxnode],dep[maxnode];
void dfs1(int u,int faa,int depth)
{
int maxsiz=0,i,j;
fa[u]=faa;dep[u]=depth;
son[u]=0;siz[u]=1;visit[u]=true;
for (i=point[u];i;i=next[i])
if (edge[(i+1)/2].flag==0&&!visit[en[i]])
{
edge[(i+1)/2].flag=1;
dfs1(en[i],u,depth+1);siz[u]+=siz[en[i]];
if (siz[en[i]]>maxsiz)
{
son[u]=en[i];maxsiz=siz[en[i]];
}
}
}
void dfs2(int u,int anc)
{
int i,j;
tid[u]=++tot1;top[u]=anc;visit[u]=false;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
if (edge[(i+1)/2].flag==1&&visit[en[i]])
dfs2(en[i],en[i]);
}
void change(int a,int b)
{
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
tch(1,1,n,tid[top[a]],tid[a]);
a=fa[top[a]];
}
if (dep[a]>dep[b]) swap(a,b);
if (a!=b) tch(1,1,n,tid[son[a]],tid[b]);
}
int query(int a,int b)
{
int ans=0;
while(top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ans+=task(1,1,n,tid[top[a]],tid[a]);
a=fa[top[a]];
}
if (dep[a]>dep[b]) swap(a,b);
if (a!=b) ans+=task(1,1,n,tid[son[a]],tid[b]);
return ans;
}
}tree;
int main()
{
freopen("moe.in","r",stdin);
freopen("moe.out","w",stdout);
int m,i,j,c,a,b,tt=0;
scanf("%d%d",&n,&m);
for (i=1;i<=m;++i){scanf("%d%d",&a,&b);add(a,b);}
while(scanf("%d",&c)==1)
{
if (c==-1) break;
scanf("%d%d",&a,&b);
ask[++tt][0]=c;ask[tt][1]=a;ask[tt][2]=b;
if (!c) edge[dui[a][b]].flag=-1;
}
tree.dfs1(1,0,1);tree.dfs2(1,1);build(1,1,n);
for (i=1;i<=tot;++i)
if (edge[i].flag==0) tree.change(edge[i].st,edge[i].en);
for (i=tt;i>=1;--i)
{
if (ask[i][0]==0) tree.change(ask[i][1],ask[i][2]);
else ask[i][3]=tree.query(ask[i][1],ask[i][2]);
}
for (i=1;i<=tt;++i)
if (ask[i][0]) printf("%d\n",ask[i][3]);
fclose(stdin);
fclose(stdout);
}
sdoi2014 旅行
题目大意:给定一棵树和树上节点的颜色和权值,求两点路径上的某种颜色的权值和和权值最大值。
思路:树链剖分+动态开点线段树。对每种颜色建线段树,然后更新就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 100005
#define inf 2100000000
using namespace std;
struct use{
int ls,rs,l,r,maxn,sum;
}t[maxm*100]={0};
int wi[maxm]={0},ci[maxm]={0},point[maxm]={0},en[maxm*2]={0},next[maxm*2]={0},tot=0,n,sum=0,
id[maxm]={0},root[maxm]={0};
char ss[10];
void add(int u,int v){
next[++tot]=point[u];point[u]=tot;en[tot]=v;
next[++tot]=point[v];point[v]=tot;en[tot]=u;
}
void updata(int i){
t[i].maxn=max(t[t[i].ls].maxn,t[t[i].rs].maxn);
t[i].sum=t[t[i].ls].sum+t[t[i].rs].sum;
}
void tins(int &i,int l,int r,int x,int w,int kk){
if (!i){t[i=++sum].l=l;t[i].r=r;t[i].maxn=-inf;}
if (l==r){
if (kk>0) t[i].maxn=t[i].sum=w;
else{t[i].maxn=-inf;t[i].sum=0;}
return;
}int mid=(l+r)/2;
if (x<=mid) tins(t[i].ls,l,mid,x,w,kk);
else tins(t[i].rs,mid+1,r,x,w,kk);
updata(i);
}
int tsum(int i,int l,int r,int ll,int rr){
int mid,ans=0;if (!i) return 0;
if (ll<=l&&r<=rr) return t[i].sum;
mid=(l+r)/2;
if (ll<=mid) ans+=tsum(t[i].ls,l,mid,ll,rr);
if (rr>mid) ans+=tsum(t[i].rs,mid+1,r,ll,rr);
return ans;
}
int tmax(int i,int l,int r,int ll,int rr){
int mid,ans;ans=-inf;
if (!i) return -inf;
if (ll<=l&&r<=rr) return t[i].maxn;
mid=(l+r)/2;
if (ll<=mid) ans=max(ans,tmax(t[i].ls,l,mid,ll,rr));
if (rr>mid) ans=max(ans,tmax(t[i].rs,mid+1,r,ll,rr));
return ans;
}
struct lp{
int fa[maxm],dep[maxm],tid[maxm],top[maxm],son[maxm],siz[maxm];
bool visit[maxm];
void dfs1(int u,int faa,int de){
int i,j,maxsiz=0;fa[u]=faa;dep[u]=de;
son[u]=0;siz[u]=1;visit[u]=false;
for (i=point[u];i;i=next[i])
if ((j=en[i])!=faa){
dfs1(j,u,de+1);siz[u]+=siz[j];
if (siz[j]>maxsiz){maxsiz=siz[j];son[u]=j;}
}
}
void dfs2(int u,int anc){
int i,j;top[u]=anc;visit[u]=true;
tid[u]=++tot;id[tot]=u;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i])
if (!visit[j=en[i]]) dfs2(j,j);
}
int qsum(int a,int b){
int ans=0,co;co=ci[a];
while(top[a]!=top[b]){
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ans+=tsum(root[co],1,n,tid[top[a]],tid[a]);
a=fa[top[a]];
}if (dep[a]>dep[b]) swap(a,b);
ans+=tsum(root[co],1,n,tid[a],tid[b]);
return ans;
}
int qmax(int a,int b){
int ans=-inf;int co=ci[a];
while(top[a]!=top[b]){
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ans=max(ans,tmax(root[co],1,n,tid[top[a]],tid[a]));
a=fa[top[a]];
}if (dep[a]>dep[b]) swap(a,b);
ans=max(ans,tmax(root[co],1,n,tid[a],tid[b]));
return ans;
}
}tree;
int main()
{
int q,i,j,u,v;scanf("%d%d",&n,&q);
for (i=1;i<=n;++i) scanf("%d%d",&wi[i],&ci[i]);
for (i=1;i<n;++i){scanf("%d%d",&u,&v);add(u,v);}
tree.dfs1(1,0,1);tot=0;tree.dfs2(1,1);
t[0].maxn=-inf;t[0].sum=0;
for (i=1;i<=n;++i)
tins(root[ci[i]],1,n,tree.tid[i],wi[i],1);
for (i=1;i<=q;++i){
scanf("%s",&ss);scanf("%d%d",&u,&v);
if (ss[0]=='C'){
if (ss[1]=='C'){
tins(root[ci[u]],1,n,tree.tid[u],wi[u],-1);
tins(root[ci[u]=v],1,n,tree.tid[u],wi[u],1);
}
else tins(root[ci[u]],1,n,tree.tid[u],wi[u]=v,1);
}else{
if (ss[1]=='S') printf("%d\n",tree.qsum(u,v));
else printf("%d\n",tree.qmax(u,v));
}
}
}
bzoj4336 骑士的旅行
题目大意:给定一棵树,有m个骑士在这棵树上,查询一条链上前k个骑士的武力值,修改:1)一个骑士换一个点;2)骑士换一个武力值。
思路:树链剖分+线段树+map。因为k很小,所以可以在线段树里维护出前k大的。用map记录一下每个点上的骑士的信息,用线段树维护,树链剖分查询就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxm 40005
#define maxx 80005
using namespace std;
map<int,int> cnt[maxm];
int n,k,point[maxm]={0},en[maxx]={0},next[maxx]={0},tot=0,ti=0,id[maxm]={0};
bool visit[maxm]={false};
struct use{
int ki[21];
void init(){ki[0]=0;}
}t[maxm*4];
inline int sc(){
char ch=getchar();int x=0;
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';ch=getchar();
}return x;
}
struct uu{int po,v;}qi[maxm];
inline void add(int u,int v){
next[++tot]=point[u];point[u]=tot;en[tot]=v;
next[++tot]=point[v];point[v]=tot;en[tot]=u;
}
inline void in(int i,int x){
int tt;t[i].init();
if (!cnt[x].size()) return;
map<int,int>::iterator it;
for (it=cnt[x].end(),--it;;--it){
for (tt=min(it->second,k-t[i].ki[0]);tt;--tt)
t[i].ki[++t[i].ki[0]]=it->first;
if (t[i].ki[0]==k||it==cnt[x].begin()) break;
}
}
inline use updata(use x,use y){
use cc;cc.init();
int i=1,j=1;
while(i<=x.ki[0]&&j<=y.ki[0]&&cc.ki[0]<k){
if (x.ki[i]>=y.ki[j])
cc.ki[++cc.ki[0]]=x.ki[i++];
else cc.ki[++cc.ki[0]]=y.ki[j++];
}if (cc.ki[0]<k){
if (i<=x.ki[0])
for (;i<=x.ki[0]&&cc.ki[0]<k;++i)
cc.ki[++cc.ki[0]]=x.ki[i];
else
for (;j<=y.ki[0]&&cc.ki[0]<k;++j)
cc.ki[++cc.ki[0]]=y.ki[j];
}return cc;
}
inline void build(int i,int l,int r){
if (l==r){in(i,id[l]);return;}
int mid=(l+r)>>1;
build(i<<1,l,mid);build(i<<1|1,mid+1,r);
t[i]=updata(t[i<<1],t[i<<1|1]);
}
inline void tch(int i,int l,int r,int x){
if (l==r){in(i,id[l]);return;}
int mid=(l+r)>>1;
if (x<=mid) tch(i<<1,l,mid,x);
else tch(i<<1|1,mid+1,r,x);
t[i]=updata(t[i<<1],t[i<<1|1]);
}
inline use task(int i,int l,int r,int ll,int rr){
use cc;cc.init();
if (ll<=l&&r<=rr) return t[i];
int mid=(l+r)>>1;
if (ll<=mid) cc=updata(cc,task(i<<1,l,mid,ll,rr));
if (rr>mid) cc=updata(cc,task(i<<1|1,mid+1,r,ll,rr));
return cc;
}
struct lp{
int fa[maxm],dep[maxm],tid[maxm],top[maxm],son[maxm],siz[maxm];
inline void dfs1(int u,int ff,int de){
int i,v,maxsiz=0;dep[u]=de;
siz[u]=1;son[u]=0;fa[u]=ff;
for (i=point[u];i;i=next[i]){
if ((v=en[i])==ff) continue;
dfs1(v,u,de+1);siz[u]+=siz[v];
if (siz[v]>maxsiz){maxsiz=siz[v];son[u]=v;}
}
}
inline void dfs2(int u,int anc){
int i,v;top[u]=anc;visit[u]=true;
tid[u]=++ti;id[ti]=u;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i]){
if (visit[v=en[i]]) continue;
dfs2(v,v);
}
}
inline use ask(int x,int y){
use cc;cc.init();
while(top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
cc=updata(cc,task(1,1,n,tid[top[x]],tid[x]));
x=fa[top[x]];
}if (dep[x]>dep[y]) swap(x,y);
cc=updata(cc,task(1,1,n,tid[x],tid[y]));
return cc;
}
}tree;
int main(){
int m,i,j,u,v,q,ti,xi,yi;
use ci;n=sc();
for (i=1;i<n;++i){u=sc();v=sc();add(u,v);}
tree.dfs1(1,0,1);tree.dfs2(1,1);m=sc();
for (i=1;i<=m;++i){
qi[i].v=sc();qi[i].po=sc();
++cnt[qi[i].po][qi[i].v];
}q=sc();k=sc();build(1,1,n);
for (i=1;i<=q;++i){
ti=sc();xi=sc();yi=sc();
if (ti==1){
ci=tree.ask(xi,yi);
if (!ci.ki[0]) printf("-1\n");
else{
for (j=1;j<=ci.ki[0];++j) printf("%d ",ci.ki[j]);
printf("\n");
}
}if (ti==2){
--cnt[qi[xi].po][qi[xi].v];tch(1,1,n,tree.tid[qi[xi].po]);
++cnt[qi[xi].po=yi][qi[xi].v];tch(1,1,n,tree.tid[qi[xi].po]);
}if (ti==3){
--cnt[qi[xi].po][qi[xi].v];
++cnt[qi[xi].po][qi[xi].v=yi];
tch(1,1,n,tree.tid[qi[xi].po]);
}
}
}
bzoj3626 LCA
题目大意:给定一棵树,每个询问是求sigma(i=l~r)dep(lca(i,z))。
思路:容斥+树链剖分。答案显然是1~l-1的和-1~r的和,所以要求1~i与z的lca的深度和。离线操作,把所有的l、r排序,把1~n依次加入树中,所以就是求树中有的点和z的lca的dep和,因为lca的dep和就是z到根的路径上,每个点的不在这条链上的孩子的个数乘这个点的dep,这个可以用链剖来求,建两棵线段树:一棵维护树上那些点标记,一棵维护这一段区间对应点的答案(这个答案是这个点的子树中不再这个点所在重链的点的个数*dep),查询的时候要在轻重链的地方式子算一下,插入的时候插给这个点到1的路径上所有轻重链交替的点就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 50005
#define maxe 100005
#define p 201314
#define LL long long
using namespace std;
struct use{
int x,z,po;
bool operator<(const use&xx)const{
return x==xx.x ? z<xx.z : x<xx.x;
}
}li[maxm],ri[maxm],lr[maxe];
int point[maxm]={0},next[maxm]={0},en[maxm]={0},tot=0,id[maxm],ti=0,n,la[maxm]={0},
tree[maxm*4]={0},fa[maxm],tid[maxm],top[maxm],son[maxm];
LL t[maxm*4]={0LL},sizb[maxm]={0LL},siz[maxm],dep[maxm],ans[maxm]={0LL};
bool visit[maxm]={false};
void add(int u,int v){next[++tot]=point[u];point[u]=tot;en[tot]=v;}
LL task(int i,int l,int r,int ll,int rr){
if (ll<=l&&r<=rr) return t[i];
int mid=l+r>>1;LL ans=0LL;
if (ll<=mid) ans+=task(i<<1,l,mid,ll,rr);
if (rr>mid) ans+=task(i<<1|1,mid+1,r,ll,rr);
return ans;
}
void tch(int i,int l,int r,int x){
if (l==r){t[i]=dep[id[l]]*sizb[id[l]]%p;return;}
int mid=l+r>>1;
if (x<=mid) tch(i<<1,l,mid,x);
else tch(i<<1|1,mid+1,r,x);
t[i]=(t[i<<1]+t[i<<1|1])%p;
}
void change(int i,int l,int r,int x){
if (l==r){tree[i]=1;return;}
int mid=l+r>>1;
if (x<=mid) change(i<<1,l,mid,x);
else change(i<<1|1,mid+1,r,x);
tree[i]=tree[i<<1]+tree[i<<1|1];
}
int asum(int i,int l,int r,int ll,int rr){
if (ll<=l&&r<=rr) return tree[i];
int mid=l+r>>1;int sum=0;
if (ll<=mid) sum+=asum(i<<1,l,mid,ll,rr);
if (rr>mid) sum+=asum(i<<1|1,mid+1,r,ll,rr);
return sum;
}
struct lp{
void dfs1(int u,int ff,int de){
int i,j,v;LL mas=0;
dep[u]=de;fa[u]=ff;
son[u]=0;siz[u]=1LL;
for (i=point[u];i;i=next[i]){
if ((v=en[i])==ff) continue;
dfs1(v,u,de+1);siz[u]+=siz[v];
if (siz[v]>mas){mas=siz[v];son[u]=v;}
}
}
void dfs2(int u,int anc){
int i,j,v;top[u]=anc;
id[tid[u]=++ti]=u;visit[u]=true;
if (son[u]) dfs2(son[u],anc);
for (i=point[u];i;i=next[i]){
if (visit[v=en[i]]) continue;
dfs2(v,v);
}la[u]=ti;
}
void cha(int a,int b){
change(1,1,n,tid[b]);
while(top[a]!=top[b]){
if (dep[top[a]]<dep[top[b]]) swap(a,b);
++sizb[a];tch(1,1,n,tid[a]);
a=fa[top[a]];
}if (dep[a]>dep[b]) swap(a,b);
++sizb[b];tch(1,1,n,tid[b]);
}
LL ask(int a,int b){
LL ans=0LL;
if (son[b]) ans=(ans+dep[b]*asum(1,1,n,tid[son[b]],la[son[b]])%p)%p;
while(top[a]!=top[b]){
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ans=(ans+task(1,1,n,tid[top[a]],tid[a]))%p;
ans=((ans-dep[fa[top[a]]]*asum(1,1,n,tid[top[a]],la[top[a]])%p)%p+p)%p;
a=fa[top[a]];
if (son[a]) ans=(ans+dep[a]*asum(1,1,n,tid[son[a]],la[son[a]])%p)%p;
}if (dep[a]>dep[b]) swap(a,b);
ans=(ans+task(1,1,n,tid[a],tid[b]))%p;
return ans;
}
}tr;
int main(){
int q,i,j,l,r,z;LL ci;scanf("%d%d",&n,&q);
for (i=1;i<n;++i){scanf("%d",&j);add(j+1,i+1);}
for (tot=0,i=1;i<=q;++i){
scanf("%d%d%d",&li[i].x,&ri[i].x,&z);
++ri[i].x;li[i].z=ri[i].z=++z;
li[i].po=ri[i].po=i;
if (li[i].x) lr[++tot]=li[i];
if (ri[i].x) lr[++tot]=ri[i];
}tr.dfs1(1,0,1);tr.dfs2(1,1);
sort(lr+1,lr+tot+1);
for (l=i=1;i<=tot;){
j=i;while(j<tot&&lr[j+1].x==lr[i].x) ++j;
while(l<=lr[j].x) tr.cha(1,l++);
for (;i<=j;++i){
ci=tr.ask(1,lr[i].z);z=lr[i].po;
if (lr[i].x==ri[z].x) ans[z]=(ans[z]+ci)%p;
if (lr[i].x==li[z].x) ans[z]=((ans[z]-ci)%p+p)%p;
}
}for (i=1;i<=q;++i) printf("%I64d\n",ans[i]);
}
还有一种更简单的方法:离线处理,每次插入的时候就是把这个点到根上所有点的权值+1,查询的时候就是这个点到根的链的权值和。(因为这里求的是深度之和,所以每个点lca以上的所有点都要加给答案)
来源:https://www.cnblogs.com/Rivendell/p/4515395.html
