题目链接:3589:动态树
子树修改,树链查询,一看就知道是树链剖分的题
关键在于容斥,对于一堆链,如果有偶数个就加上,奇数个就减去,所以枚举子集就可以了
对于两条链,我们怎么求交?设两条链中最深的节点为a,b
求出他们的LCA,如果LCA的深度小于其中一条链的最浅节点的深度,交集为空,否则交集为LCA到深度较大的链顶形成的一条链
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=800010;
int n,m,tot=0,h[maxn],pos[maxn];
struct edge{int to,next;}G[maxn*5];
int dep[maxn],size[maxn],bin[maxn];
int fa[maxn][21],Belong[maxn],ind=0;
struct point{int a,b;}p[1000];
struct seg{
int l,r,data,sum;
seg *lc,*rc;
seg():data(0),sum(0){}
};
seg *root=new seg();
bool vis[maxn];
void add(int x,int y){
G[++tot].to=y; G[tot].next=h[x]; h[x]=tot;
}
void dfs1(int x,int deep){
dep[x]=deep; size[x]=1; vis[x]=1;
for (int i=1;i<=19;++i){
if (dep[x]<(1<<i)) break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for (int i=h[x];i;i=G[i].next){
int v=G[i].to;
if (vis[v]) continue;
fa[v][0]=x;
dfs1(v,deep+1);
size[x]+=size[v];
}
}
void dfs2(int x,int L){
int k=0; ++ind; Belong[x]=L; pos[x]=ind;
for (int i=h[x];i;i=G[i].next)
if (dep[x]<dep[G[i].to]&&size[G[i].to]>size[k])
k=G[i].to;
if (!k) return; dfs2(k,L);
for (int i=h[x];i;i=G[i].next)
if (dep[x]<dep[G[i].to]&&k!=G[i].to)
dfs2(G[i].to,G[i].to);
}
void push_up(seg *p){
if (p->l+1==p->r) return; p->sum=0;
if (p->lc) p->sum+=p->lc->sum;
if (p->rc) p->sum+=p->rc->sum;
}
void build(seg *p,int l,int r){
p->l=l; p->r=r;
if (l+1==r){
p->lc=p->rc=NULL;return;
}else if (l+1<r){
int mid=(l+r)>>1;
p->lc=new seg();
p->rc=new seg();
if (l<mid) build(p->lc,l,mid);
else p->lc=NULL;
if (mid<r) build(p->rc,mid,r);
else p->rc=NULL;
}
}
int query(int a,int b){
if (dep[a]<dep[b]) swap(a,b);
int t=dep[a]-dep[b];
for (int i=19;~i;--i)
if (t&(1<<i)) a=fa[a][i];
for (int i=19;~i;i--)
if (fa[a][i]!=fa[b][i]){
a=fa[a][i];b=fa[b][i];}
if (a==b) return a;
else return fa[a][0];
}
void push_down(seg *p){
if (p->l+1==p->r) return;
if (p->lc) p->lc->sum+=(p->lc->r-p->lc->l)*p->data,
p->lc->data+=p->data;
if (p->rc) p->rc->sum+=(p->rc->r-p->rc->l)*p->data,
p->rc->data+=p->data;
p->data=0;
}
void update(seg *p,int l,int r,int v){
push_down(p);
if (l<=p->l&&p->r<=r) {
int len=p->r-p->l; p->sum+=v*len;
p->data+=v; return;
}else{
int mid=(p->l+p->r)>>1;
if (l<mid) update(p->lc,l,r,v);
if (mid<r) update(p->rc,l,r,v);
push_up(p);
}
}
int ask(seg *p,int l,int r){
push_down(p);
if (l<=p->l&&p->r<=r) return p->sum;
else{
int mid=(p->l+p->r)>>1,ret=0;
if (l<mid) ret+=ask(p->lc,l,r);
if (mid<r) ret+=ask(p->rc,l,r);
return ret;
}
}
int getnum(int x,int y){
int sum=0;
while (Belong[x]!=Belong[y]){
if (dep[Belong[x]]<dep[Belong[y]]) swap(x,y);
sum+=ask(root,pos[Belong[x]],pos[x]+1);
x=fa[Belong[x]][0];
} if (dep[x]<dep[y]) swap(x,y);
sum+=ask(root,pos[y],pos[x]+1);
return sum;
}
point getdel(point a,point b){
int lca=query(a.a,b.a); point ret;
if (dep[lca]<dep[a.b]||dep[lca]<dep[b.b]){
ret.a=ret.b=-1; return ret;
}ret.a=lca;ret.b=dep[a.b]>dep[b.b]?a.b:b.b;
return ret;
}
int calc(int x){
point tmp; tmp.a=tmp.b=0;
for (int i=1;x;i++,x>>=1) if (x&1){
if (!tmp.a) tmp=p[i];
else tmp=getdel(tmp,p[i]);
if (tmp.a==-1) return 0;
}return getnum(tmp.a,tmp.b);
}
void getans(int k){
int ans=0;
for (int i=1;i<(1<<k);++i)
ans+=calc(i)*(bin[i]&1?1:-1);
printf("%d\n",ans&2147483647);
}
int main(){
scanf("%d",&n);
for (int i=1;i<n;++i){
int x,y; scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs1(1,1); dfs2(1,1);
build(root,1,n+1);
for (int i=1;i<1<<5;++i) bin[i]=bin[i>>1]+(i&1);
scanf("%d",&m);
for (int i=1;i<=m;++i){
int opt,x,y,k;
scanf("%d",&opt);
if (!opt){
scanf("%d%d",&x,&y);
update(root,pos[x],pos[x]+size[x],y);
}else if (opt){
scanf("%d",&k);
for (int j=1;j<=k;++j){
p[j].a=p[j].b=0;
scanf("%d%d",&p[j].a,&p[j].b);
if (dep[p[j].a]<dep[p[j].b]) swap(p[j].a,p[j].b);
}getans(k);
}
}
}