【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草
约翰有 N 个牧场,编号为 1 到 N。它们之间有 N − 1 条道路,每条道路连接两个牧场。通过这
些道路,所有牧场都是连通的。
刚开始的时候,所有道路都是光秃秃的,没有青草。约翰会在一些道路上批量种草。每次开始种
草的时候,约翰会选择一个牧场作为起点,一个牧场作为终点,找到从起点到终点的最短路径,在这
条路径上所有的道路上分别种下一棵新的青草。
贝西在监督约翰的工作,她迫不及待地想知道每条道路上已经有多少青草了。约翰的工作总是被
贝西打断,他不胜其烦,所以请你来帮忙回答贝西的问题。约翰的工作和贝西的询问是穿插进行的,
输入数据将会依次出现 M 个事件,以字符 P 开头的事件表示约翰在一条路径上种植了青草,以字符
Q 开头的事件表示贝西在查询一条道路上有多少青草。
输入格式
• 第一行:两个整数 N 和 M, 2 ≤ N ≤ 105 , 1 ≤ M ≤ 105
• 第二行到第 N 行:第 i + 1 行有两个整数 Ui 和 Vi,表示第 i 条道路连接的两个牧场编号,
1 ≤ Ui,Vi ≤ N
• 第 N + 1 行到第 N + Q 行:每行首先由一个大写字母:
– 如果是 P,随后会有两个整数 A 和 B,表示约翰在从 A 通向 B 的每条道路上都新种了一
棵青草, 1 ≤ A,B ≤ N
– 如果是 Q,随后会有两个整数 A 和 B,表示贝西查询一条道路上的青草数量, A 和 B 是
这条道路的两个端点, 1 ≤ A,B ≤ N,保证输入数据中存在一条 A 到 B 的道路
输出格式
• 对每个查询请求,输出该条道路上青草的数量,以换行符分隔
样例输入
4 6
1 4
2 4
3 4
P 2 3
P 1 3
Q 3 4
P 1 4
Q 2 4
Q 1 4
样例输出
212
【分析】
因为是树状数组专题,于是我打了树状数组没有打线段树。
表示人生第一次树状数组的区间修改和区间查询(我太垃圾..
其实比线段树可还是短多了,就是维护两个东西的前缀和,一个是delta[i],一个是delta[i]*i,delta[i]表示i~n的共同增量。
具体看我转的那篇东西:http://www.cnblogs.com/Konjakmoyu/p/5981935.html
然后就是树剖啦ORZ,好多年没打了居然还能打出来ORZ...
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 100010 10 11 struct node 12 { 13 int x,y,next; 14 }t[Maxn*2];int len; 15 int first[Maxn]; 16 17 void ins(int x,int y) 18 { 19 t[++len].x=x;t[len].y=y; 20 t[len].next=first[x];first[x]=len; 21 } 22 23 char s[10]; 24 25 int sm[Maxn],son[Maxn],fa[Maxn],dep[Maxn]; 26 void dfs(int x,int f) 27 { 28 sm[x]=1;son[x]=0;fa[x]=f;dep[x]=dep[f]+1; 29 for(int i=first[x];i;i=t[i].next) if(t[i].y!=f) 30 { 31 int y=t[i].y; 32 dfs(y,x); 33 sm[x]+=sm[y]; 34 if(sm[y]>sm[son[x]]) son[x]=y; 35 } 36 } 37 38 int tp[Maxn],dfn[Maxn],cnt; 39 void dfs2(int x,int tpp) 40 { 41 if(x==0) return; 42 dfn[x]=++cnt;tp[x]=tpp; 43 dfs2(son[x],tpp); 44 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]) 45 { 46 int y=t[i].y; 47 if(y==son[x]) continue; 48 dfs2(y,y); 49 } 50 } 51 52 int c1[Maxn],c2[Maxn]; 53 54 void ffind(int x,int y,int c) 55 { 56 for(int i=x;i<=cnt;i+=i&(-i)) 57 c1[i]+=c,c2[i]+=c*x; 58 y++; 59 for(int i=y;i<=cnt;i+=i&(-i)) 60 c1[i]+=-c,c2[i]+=(-c)*y; 61 } 62 63 int get_ans(int x,int y) 64 { 65 int ans=0; 66 for(int i=y;i>=1;i-=i&(-i)) 67 ans+=(y+1)*c1[i]-c2[i]; 68 x--; 69 for(int i=x;i>=1;i-=i&(-i)) 70 ans-=(x+1)*c1[i]-c2[i]; 71 return ans; 72 } 73 74 void change(int x,int y) 75 { 76 int tt; 77 while(tp[x]!=tp[y]) 78 { 79 if(dep[tp[x]]>dep[tp[y]]) 80 { 81 tt=x,x=y,y=tt; 82 } 83 ffind(dfn[tp[y]],dfn[y],1); 84 y=fa[tp[y]]; 85 } 86 if(x==y) return; 87 if(dep[x]>dep[y]) tt=x,x=y,y=tt; 88 ffind(dfn[x]+1,dfn[y],1); 89 } 90 91 int query(int x,int y) 92 { 93 int ans=0; 94 int tt; 95 while(tp[x]!=tp[y]) 96 { 97 if(dep[tp[x]]>dep[tp[y]]) 98 { 99 tt=x,x=y,y=tt; 100 } 101 ans+=get_ans(dfn[tp[y]],dfn[y]); 102 y=fa[tp[y]]; 103 } 104 if(x==y) return ans; 105 if(dep[x]>dep[y]) tt=x,x=y,y=tt; 106 ans+=get_ans(dfn[x]+1,dfn[y]); 107 return ans; 108 } 109 110 int main() 111 { 112 int n,m; 113 scanf("%d%d",&n,&m); 114 len=0; 115 memset(first,0,sizeof(first)); 116 for(int i=1;i<n;i++) 117 { 118 int x,y; 119 scanf("%d%d",&x,&y); 120 ins(x,y);ins(y,x); 121 } 122 sm[0]=0;dep[0]=0; 123 dfs(1,0); 124 cnt=0; 125 dfs2(1,1); 126 127 memset(c1,0,sizeof(c1)); 128 memset(c2,0,sizeof(c2)); 129 for(int i=1;i<=m;i++) 130 { 131 int x,y; 132 scanf("%s%d%d",s,&x,&y); 133 if(s[0]=='P') 134 { 135 change(x,y); 136 } 137 else 138 { 139 printf("%d\n",query(x,y)); 140 } 141 } 142 return 0; 143 }
2016-10-28 09:56:44