【题目描述】
给定一棵树,要求维护以下操作:
1、M u 将u节点反色
2、Q u 查询u到所有黑色节点距离和
【输入格式】
第一行n,m 表示节点总数和操作次数
之后n-1行,每行u,v表示两个端点,w表示边权
之后m行,操作如题意
n,m<=200000,边权<=1000
一开始所有点均为白色
【输出格式】
输出每次Q的答案
【样例输入】
7 5
2 1 144
3 2 361
4 3 236
5 3 697
6 2 140
7 5 718
Q 4
M 4
Q 5
Q 1
Q 7
【样例输出】
0
933
741
1651
题解:
和上一题差不多,多了一个修改操作。
还是动态点分,每个节点储存两个数,分别表示整棵子树到根和到根节点的父节点的距离和。
容斥一下就好。
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #define inf (2147483647) 9 using namespace std; 10 int n,m,a[200005],lim; 11 struct node{ 12 int next,to,dis; 13 }edge[400005]; 14 int head[200005],size; 15 void putin(int from,int to,int dis){ 16 size++; 17 edge[size].next=head[from]; 18 edge[size].to=to; 19 edge[size].dis=dis; 20 head[from]=size; 21 } 22 int fa[200005][20],dis[200005],depth[200005]; 23 void dfs1(int r,int father){ 24 int i; 25 fa[r][0]=father; 26 depth[r]=depth[father]+1; 27 for(i=head[r];i!=-1;i=edge[i].next){ 28 int y=edge[i].to; 29 if(y!=father){ 30 dis[y]=dis[r]+edge[i].dis; 31 dfs1(y,r); 32 } 33 } 34 } 35 void make(){ 36 lim=log(n)/log(2); 37 for(int i=1;i<=lim;i++) 38 for(int j=1;j<=n;j++) 39 fa[j][i]=fa[fa[j][i-1]][i-1]; 40 } 41 int LCA(int x,int y){ 42 if(depth[x]<depth[y])swap(x,y); 43 for(int i=lim;i>=0;i--) 44 if(depth[fa[x][i]]>=depth[y]) 45 x=fa[x][i]; 46 if(x!=y){ 47 for(int i=lim;i>=0;i--) 48 if(fa[x][i]!=fa[y][i]) 49 x=fa[x][i],y=fa[y][i]; 50 x=fa[x][0]; 51 y=fa[y][0]; 52 } 53 return x; 54 } 55 int dist(int x,int y){ 56 int lca=LCA(x,y); 57 return dis[x]+dis[y]-dis[lca]*2; 58 } 59 int tot,root,vis[200005],d[200005],ff[200005],cnt[200005]; 60 void getroot(int r,int father){ 61 int i; 62 cnt[r]=1;d[r]=0; 63 for(i=head[r];i!=-1;i=edge[i].next){ 64 int y=edge[i].to; 65 if(y!=father&&!vis[y]){ 66 getroot(y,r); 67 cnt[r]+=cnt[y]; 68 d[r]=max(d[r],cnt[y]); 69 } 70 } 71 d[r]=max(d[r],tot-cnt[r]); 72 if(d[root]>d[r])root=r; 73 } 74 void buildtree(int r,int father){ 75 int i,all=tot; 76 ff[r]=father;vis[r]=1; 77 for(i=head[r];i!=-1;i=edge[i].next){ 78 int y=edge[i].to; 79 if(!vis[y]){ 80 if(cnt[y]>cnt[r])cnt[y]=all-cnt[r];tot=cnt[y]; 81 root=0;getroot(y,r);buildtree(root,r); 82 } 83 } 84 } 85 int p[200005][2]; 86 void insert(int x,int v){ 87 int i; 88 for(i=x;ff[i];i=ff[i]){ 89 int len=dist(x,ff[i]); 90 p[i][1]+=len*v; 91 p[ff[i]][0]+=len*v; 92 } 93 for(i=x;i;i=ff[i])cnt[i]+=v; 94 } 95 int find(int x){ 96 int i,ans=p[x][0]; 97 for(i=x;ff[i];i=ff[i]){ 98 int len=dist(x,ff[i]); 99 ans+=p[ff[i]][0]; 100 ans-=p[i][1]; 101 ans+=(cnt[ff[i]]-cnt[i])*len; 102 } 103 return ans; 104 } 105 void clean(){ 106 memset(head,-1,sizeof(head)); 107 size=0; 108 } 109 int main(){ 110 freopen("A_Tree.in","r",stdin); 111 freopen("A_Tree.out","w",stdout); 112 int i,j; 113 clean(); 114 scanf("%d%d",&n,&m); 115 for(i=1;i<n;i++){ 116 int u,v,l; 117 scanf("%d%d%d",&u,&v,&l); 118 putin(u,v,l); 119 putin(v,u,l); 120 } 121 dfs1(1,0);make(); 122 tot=n;root=0;d[0]=inf; 123 getroot(1,0);buildtree(root,0); 124 for(i=1;i<=n;i++)if(!ff[i]){root=i;break;} 125 char s[10]; 126 memset(cnt,0,sizeof(cnt)); 127 while(m--){ 128 scanf("%s",s); 129 if(s[0]=='Q'){ 130 int x; 131 scanf("%d",&x); 132 printf("%d ",find(x)); 133 } 134 else{ 135 int x; 136 scanf("%d",&x); 137 a[x]^=1; 138 if(a[x])insert(x,1); 139 else insert(x,-1); 140 } 141 } 142 return 0; 143 }