[USACO11DEC]Grass Planting
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[USACO11DEC]Grass Planting相关的知识,希望对你有一定的参考价值。
题目大意:
有一棵结点个数为n的树,有m个操作,可以将一段路径上每条边的权值+1或询问某一个边的权值。
思路:
树链剖分+线段树。
轻重链划分本身比较简单,主要需要思考如何用线段树维护每条链。
当x,y不在同一条链上时,先处理深度大的链,对于每一个链,建立一棵动态开点的线段树,用一个数组len顺序记录每一条边在链中的编号,然后维护len[x]+1到len[top[x]]这一区间的权值即可。
处理轻边时,可以直接用一个数组保存它的权值。
因为轻重边肯定是交替的,因此每次循环都可以先维护一个重边,再维护一个轻边。
最后x和y肯定会跳到同一条重链上,这时候我们只要维护这条链上从len[x]+1到len[y]的边权即可(实际上就是一个找LCA的过程)。
询问则比较简单,因为询问的是一条边而非一条路径,因此直接分类讨论这条边是轻边还是重边即可。(网上那么多题解都是没有读题吗?)
细节:
轻边不能直接对边上某一点开线段树维护,因为如果这个点刚好是某一个重链的第一个点,就会出现轻重边共用同一棵线段树的情况。
这题是USACO月赛题,官方题解是用树状数组维护,但是他们是对整棵树开树状数组,所以还是没我跑得快。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 inline int getint() { 5 char ch; 6 while(!isdigit(ch=getchar())); 7 int x=ch^‘0‘; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 9 return x; 10 } 11 const int V=100001; 12 std::vector<int> e[V]; 13 inline void add_edge(const int u,const int v) { 14 e[u].push_back(v); 15 } 16 class SegmentTree { 17 private: 18 int val[V<<1],left[V<<1],right[V<<1]; 19 int sz; 20 int newnode() { 21 return ++sz; 22 } 23 public: 24 int root[V]; 25 void modify(int &p,const int b,const int e,const int l,const int r) { 26 if(!p) p=newnode(); 27 if((b==l)&&(e==r)) { 28 val[p]++; 29 return; 30 } 31 int mid=(b+e)>>1; 32 if(l<=mid) modify(left[p],b,mid,l,std::min(mid,r)); 33 if(r>mid) modify(right[p],mid+1,e,std::max(mid+1,l),r); 34 } 35 int query(int &p,const int b,const int e,const int x) { 36 if(!p) return 0; 37 if(b==e) return val[p]; 38 int mid=(b+e)>>1; 39 return (x<=mid?query(left[p],b,mid,x):query(right[p],mid+1,e,x))+val[p]; 40 } 41 }; 42 SegmentTree t; 43 int size[V],son[V],top[V],len[V],dep[V],par[V]; 44 void dfs1(const int x,const int p) { 45 size[x]=1; 46 dep[x]=dep[p]+1; 47 par[x]=p; 48 for(unsigned i=0;i<e[x].size();i++) { 49 int &y=e[x][i]; 50 if(y==p) continue; 51 dfs1(y,x); 52 size[x]+=size[y]; 53 if(size[y]>size[son[x]]) son[x]=y; 54 } 55 } 56 void dfs2(const int x) { 57 top[x]=(x==son[par[x]])?top[par[x]]:x; 58 for(unsigned i=0;i<e[x].size();i++) { 59 int &y=e[x][i]; 60 if(y==par[x]) continue; 61 dfs2(y); 62 len[x]=len[son[x]]+1; 63 } 64 } 65 int val[V]; 66 inline void modify(int x,int y) { 67 while(top[x]!=top[y]) { 68 if(dep[top[x]]<dep[top[y]]) std::swap(x,y); 69 if(x!=top[x]) t.modify(t.root[top[x]],1,len[top[x]],len[x]+1,len[top[x]]); 70 val[top[x]]++; 71 x=par[top[x]]; 72 } 73 if(x==y) return; 74 if(dep[x]<dep[y]) std::swap(x,y); 75 t.modify(t.root[top[x]],1,len[top[x]],len[x]+1,len[y]); 76 } 77 inline int query(int x,int y) { 78 if(dep[x]<dep[y]) std::swap(x,y); 79 return top[x]==top[y]?t.query(t.root[top[x]],1,len[top[x]],len[y]):val[x]; 80 } 81 int main() { 82 int n=getint(),m=getint(); 83 for(int i=1;i<n;i++) { 84 int u=getint(),v=getint(); 85 add_edge(u,v); 86 add_edge(v,u); 87 } 88 dfs1(1,0); 89 dfs2(1); 90 while(m--) { 91 char op[2]; 92 scanf("%s",op); 93 int x=getint(),y=getint(); 94 if(op[0]==‘P‘) { 95 modify(x,y); 96 } 97 else { 98 printf("%d\n",query(x,y)); 99 } 100 } 101 return 0; 102 }
以上是关于[USACO11DEC]Grass Planting的主要内容,如果未能解决你的问题,请参考以下文章
AC日记——[USACO11DEC]牧草种植Grass Planting 洛谷 P3038
[USACO11DEC] 牧草种植Grass Planting
LuoguP3038/[USACO11DEC]牧草种植Grass Planting树链剖分+树状数组树状数组的区间修改与区间查询