Hdu 5029 Relief grain(树链剖分)
来源:互联网 发布:淘宝上的美瞳能买吗 编辑:程序博客网 时间:2024/05/16 10:58
题目大意:
给出一棵树。
然后有m个操作,每个操作都在两点的路径上分配不同的粮食。
最后要求输出所有村庄有的最多的粮食的种类。
思路分析:
一眼就看得出来是树链剖分的题目。
现在的问题就是,每一次操作,如何维护每个点的最多的食物编号,以及最多的食物的数量。要记录这两个值是肯定的。
首先可以想到将所有的操作按照z排序。这样每一回合操作,称一回合为处理同一种颜色。一回合结束之后,后面的操作就不会影响前面取得的最大值。因为后面的操作的食物的种类不一样,是不可以再继续累加的。
然后可以发现一个规律,就是每处理完一种颜色之后,在线段树上,颜色比这种颜色编号大的颜色都存在了这个节点的树形结构的上面。也就是父亲节点甚至是父亲节点的父亲节点。
所以我们就直接考虑pushdown部分吧,这是这道题目的难点。
假设操作只有 2 3 4这三种食物。
我们首先先处理完了所有食物种类为2的所有操作。
现在在处理种类为3的操作。如果这个操作的指定区间的lazy标记的颜色也是3.那么就直接累加,毫无疑问。但是如果这个区间是2...由于我们现在还在处理3,你不确定后面还有多少种类为3的操作,所以我们就要将这个种类为2的lazy往下推(用递归的pushdown实现)。然后将3更新。
按照如上操作处理了3之后。
现在我们处理种类为4的。我们注意到之前说的规律。
2一定在3下面,那么4的下面也之后有3.
所以现在种类4的操作,碰到了4.那么也是直接累加无疑问。好,如果碰到操作三,按照我们上述的,要将3pushdown。但是,在pushdown3的过程中,这个3又会遇到lazy颜色为2的。产生冲突。但是我们注意到,如果是4将3推下去,而且3又碰到了2,也就以为着,这个子树只有一个节点的lazy是3了。为什么,还是那个规律。自己想一下就明白。
所以意思就是下面不会有三,那个节点的全部三就是所有操作的全部三。当递推下的3的数量比碰到的那个2的数量还要小,也就意味着以下的节点的答案不可能是3 的。
但是如果2比三小,可能这下面还有一些2没有累加,所以就把2递推下去,再递推3下去,再更新4.
好,现在我们分析时间复杂度。
首先m此操作。
然后查找熟练logn
线段树更新logn
那么这个pushdown的递归呢。
因为递归层数是不会超过logn的。
所以最多也就是 m*log^3...
当然最优解肯定不是这个。。。
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <utility>#pragma comment(linker,"/STACk:10240000,10240000")#define maxn 100005#define lson num<<1,s,mid#define rson num<<1|1,mid+1,e#define mid ((s+e)>>1)using namespace std;int next[maxn<<1],to[maxn<<1],head[maxn],tot;//临界表int pre[maxn],root[maxn],siz[maxn],son[maxn],w[maxn],dep[maxn],id;//原树的父亲 链上的根 siz 有最大siz的子树 重新分配的id 深度 getid中来计数的pair<int,int>ans[maxn<<2];//线段树变量pair<int,int>cov[maxn<<2];int n,cur;void init(){ pre[1]=0; dep[1]=0; tot=0;id=0; memset(head,0,sizeof head);}void addedge(int u,int v){ tot++; next[tot]=head[u]; to[tot]=v; head[u]=tot;}void dfs(int now)//to get size,son,dep,pre...{ son[now]=0; siz[now]=1; for(int p =head[now]; p ; p=next[p]) { int t=to[p]; if(t!=pre[now]) { pre[t]=now; dep[t]=dep[now]+1; dfs(t); if(siz[t]>siz[son[now]])son[now]=t; siz[now]+=siz[t]; } }}void getid(int now,int rt)//to get w and root...{ w[now]=++id; root[now]=rt; if(son[now])getid(son[now],rt); for(int p = head[now] ; p ; p=next[p]) { int t=to[p]; if(t!=son[now]&&t!=pre[now]) getid(t,t); }}void pushdown(int num,int s,int e){ if(s==e) { cov[num].first=cov[num].second=0; return; } if(cov[num].second) { if(cov[num<<1].second==cov[num].second) cov[num<<1].first+=cov[num].first; else { if(cov[num<<1].first<cov[num].first || cov[num].second==cur) { pushdown(lson); cov[num<<1]=cov[num]; } } if(s==mid) { if(cov[num<<1].first>ans[num<<1].first) ans[num<<1]=cov[num<<1]; } if(cov[num<<1|1].second==cov[num].second) cov[num<<1|1].first+=cov[num].first; else { if(cov[num<<1|1].first<cov[num].first || cov[num].second==cur) { pushdown(rson); cov[num<<1|1]=cov[num]; } } if(mid+1==e) { if(cov[num<<1|1].first>ans[num<<1|1].first) ans[num<<1|1]=cov[num<<1|1]; } cov[num].first=cov[num].second=0; }}void build(int num,int s,int e){ ans[num].first=ans[num].second=0; cov[num].first=0; cov[num].second=0; if(s==e)return; build(lson); build(rson);}void update(int num,int s,int e,int l,int r,int val){ if(l<=s && r>=e) { if(cov[num].second==val) cov[num].first++; else { pushdown(num,s,e); cov[num].first++; cov[num].second=val; } if(s==e){ if(cov[num].first>ans[num].first) ans[num]=cov[num]; } return; } pushdown(num,s,e); if(l<=mid)update(lson,l,r,val); if(r>mid)update(rson,l,r,val);}int query(int num,int s,int e,int pos){ if(s==e)return ans[num].second; pushdown(num,s,e); if(pos<=mid)return query(lson,pos); else return query(rson,pos);}void work(int x,int y,int val){ while(root[x]!=root[y]) { if(dep[root[x]]<dep[root[y]])swap(x,y); update(1,1,n,w[root[x]],w[x],val); x=pre[root[x]]; } if(dep[x]>dep[y])swap(x,y); update(1,1,n,w[x],w[y],val);}struct node{ int x,y,z; bool operator < (const node &cmp)const{ return z<cmp.z; }}line[maxn];int main(){ int m; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0 && m==0)break; init(); for(int i=1;i<=n-1;i++) { int s,e; scanf("%d%d",&s,&e); addedge(s,e); addedge(e,s); } dfs(1); getid(1,1); build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d%d%d",&line[i].x,&line[i].y,&line[i].z); } sort(line+1,line+1+m); for(int i=1;i<=m;i++){ int x,y,z; cur=line[i].z; work(line[i].x,line[i].y,line[i].z); } cur=-1; for(int i=1;i<=n;i++) { printf("%d\n",query(1,1,n,w[i])); } } return 0;}/*2 41 21 1 11 2 22 2 22 2 15 31 23 13 45 32 3 31 5 23 3 35 41 22 33 44 51 5 11 3 21 2 21 1 35 51 22 33 44 51 1 11 2 11 3 21 5 21 3 25 51 22 33 44 51 2 11 2 11 3 21 1 21 1 25 101 22 33 44 51 1 11 1 11 1 21 1 21 1 11 1 21 1 31 1 31 1 31 1 30 0*/
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <vector>#pragma comment(linker,"/STACk:10240000,10240000")#define maxn 100005#define lson num<<1,s,mid#define rson num<<1|1,mid+1,eusing namespace std;int next[maxn<<1],to[maxn<<1],head[maxn],tot;//临界表int pre[maxn],root[maxn],siz[maxn],son[maxn],w[maxn],dep[maxn],fp[maxn],id;//原树的父亲 链上的根 siz 有最大siz的子树 重新分配的id 深度 getid中来计数的int mx[maxn<<2],mz[maxn<<2];//线段树变量int n;void init(){ pre[1]=0; dep[1]=0; tot=0;id=0; memset(head,0,sizeof head);}void addedge(int u,int v){ tot++; next[tot]=head[u]; to[tot]=v; head[u]=tot;}void dfs(int now)//to get size,son,dep,pre...{ son[now]=0; siz[now]=1; for(int p =head[now]; p ; p=next[p]) { int t=to[p]; if(t!=pre[now]) { pre[t]=now; dep[t]=dep[now]+1; dfs(t); if(siz[t]>siz[son[now]])son[now]=t; siz[now]+=siz[t]; } }}void getid(int now,int rt)//to get w and root...{ w[now]=++id; fp[w[now]]=now; root[now]=rt; if(son[now])getid(son[now],rt); for(int p = head[now] ; p ; p=next[p]) { int t=to[p]; if(t!=son[now]&&t!=pre[now]) getid(t,t); }}void pushup(int num){ if(mx[num<<1]>=mx[num<<1|1]) { mx[num]=mx[num<<1]; mz[num]=mz[num<<1]; } else { mx[num]=mx[num<<1|1]; mz[num]=mz[num<<1|1]; }}void pushdown(int num,int s,int e){}void build(int num,int s,int e){ if(s==e) { mx[num]=0; mz[num]=s; return; } int mid=(s+e)>>1; build(lson); build(rson); pushup(num);}void update(int num,int s,int e,int pos,int val){ if(s==e) { mx[num]+=val; return; } // pushdown(num,s,e); int mid=(s+e)>>1; if(pos<=mid)update(lson,pos,val); else update(rson,pos,val); pushup(num);}vector <int> add[maxn];vector <int> sub[maxn];void work(int x,int y,int val){ while(root[x]!=root[y]) { if(dep[root[x]]<dep[root[y]])swap(x,y); add[w[root[x]]].push_back(val); sub[w[x]+1].push_back(val); //update(1,1,n,w[root[x]],w[x],val); x=pre[root[x]]; } if(dep[x]>dep[y])swap(x,y); add[w[x]].push_back(val); sub[w[y]+1].push_back(val); // update(1,1,n,w[x],w[y],val);}int save[maxn];int main(){ int m; while(scanf("%d%d",&n,&m)!=EOF) { if(!n && !m)break; init(); for(int i=1;i<=n-1;i++) { int s,e; scanf("%d%d",&s,&e); addedge(s,e); addedge(e,s); } dfs(1); getid(1,1); for(int i=1;i<=100000;i++) { add[i].clear(); sub[i].clear(); } while(m--) { int u,v,z; scanf("%d%d%d",&u,&v,&z); work(u,v,z); } build(1,1,100000); for(int i=1;i<=n;i++) { for(int j=0;j<add[i].size();j++) update(1,1,100000,add[i][j],1); for(int j=0;j<sub[i].size();j++) update(1,1,100000,sub[i][j],-1); if(mx[1]==0)save[fp[i]]=0; else save[fp[i]]=mz[1]; } for(int i=1;i<=n;i++) printf("%d\n",save[i]); } return 0;}/*2 41 21 1 11 2 22 2 22 2 15 31 23 13 45 32 3 31 5 23 3 35 41 22 33 44 51 5 11 3 21 2 21 1 35 51 22 33 44 51 1 11 2 11 3 21 5 21 3 25 51 22 33 44 51 2 11 2 11 3 21 1 21 1 25 101 22 33 44 51 1 11 1 11 1 21 1 21 1 11 1 21 1 31 1 31 1 31 1 30 0*/
- Hdu 5029 Relief grain(树链剖分)
- HDU 5029 Relief grain(树链剖分)
- hdu 5029 Relief grain 树链剖分
- hdu 5029 Relief grain 树链剖分
- HDU 5029 Relief grain
- hdu 5029 Relief grain
- HDU 5029 Relief grain (树链剖分 + 线段树)
- [HDU 5029] Relief grain (树链剖分+线段树)
- hdu 5029 Relief grain (树链剖分+线段树)
- hdu 5029 Relief grain(树链剖分+线段树)
- HDU 5029 Relief grain --树链剖分第一题
- HDU 5029Relief grain 树链剖分 好题
- HDU 5029Relief grain(树链剖分+线段树)
- hdu 5029 Relief grain(树链剖分好题)
- hdu 5029 Relief grain 树剖
- hdu 5029 Relief grain(树链剖分好题)
- HDU5029--Relief grain(树链剖分)
- 【HDU】5029 Relief grain 树链剖分+离线标记法
- IOS8新特性NSExtensionMainStoryboard (扩展)
- 初识ContentProvider
- android、Java下判断两个String是否相等 、EditText输入是否为空,限定输入数字的实现 总结
- Mesa: GeoReplicated, Near RealTime, Scalable Data Warehousing
- 给自己的备忘录——SharedPreferences
- Hdu 5029 Relief grain(树链剖分)
- Openfire开发配置,Openfire源代码配置,OpenFire二次开发配置
- Art of Multiprocessor Programming 答案 ch17
- JAVA组件焦点的特性:获取组件时其顶层组件必须为可见的
- 【最大流+输出路径】POJ-3436 ACM Computer Factory
- Linux shell脚本编写基础
- 设计数组类扩展数组的功能
- JavaFX战旗类游戏开发 第六课 移动范围的获取
- 老鸟的Python入门教程