2 4 1 2 1 1 1 1 2 2 2 2 2 2 2 1 5 3 1 2 3 1 3 4 5 3 2 3 3 1 5 2 3 3 3 0 0
1 2 2 3 3 0 2HintFor the first test case, the relief grain in the 1st village is {1, 2}, and the relief grain in the 2nd village is {1, 2, 2}. 转自 http://blog.csdn.net/u013368721/article/details/39449273题目分析:这题的方法太美妙了!
首先看到这是一颗树,那么很容易想到树链剖分。然后想到可以将查询排个序,然后每一种查询执行完以后更新每个点的最优值。但是这样进行的复杂度太高!尤其是当z给的没有一样的时候尤其如此。
那么我们是否可以找到更加高效的算法?
答案是肯定的!
先简化一下问题,如果这些操作是在线段上进行的,我们怎么求解?
我们很容易可以想到标记法:区间【L,R】染上颜色X,则位置L标记为X,表示从L开始染色X,位置R+1标记为-X,表示从R+1开始结束染色。用邻接表保存当前位置上的标记,然后从左往右,每到一个点上就把所有的标记执行了,为此我们建立一棵权值线段树,+X,我们就在位置X上+1,-X,我们就在位置X上-1,然后用maxv标记记录区间最大值。执行完这些操作以后就是查询了,顺着maxv == 最大值走,尽量往左走就行了。
然后我们回到本题,完全就是一个套路啊!
只不过把连续的区间分成logN个不是连续的区间而已。还是按照上面的操作就可以了,不过要注意扫描时的点是线段树上的点,而不是原来的点,还要映射回去。
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf -0x3f3f3f3f #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; const int maxn=101010; int p,v,tot; vector<int>G[maxn]; int siz[maxn],son[maxn],fa[maxn],deep[maxn],top[maxn],id[maxn]; int fp[maxn],maxv[maxn*4],num[maxn*4],ans[maxn]; void scanf ( int& x , char c = 0 ) { while ((c=getchar())<'0'||c>'9'); x = c - '0' ; while ( ( c = getchar () ) >= '0' && c <= '9' ) x = x * 10 + c - '0' ; } void dfs1(int u,int dep){ deep[u]=dep; siz[u]=1,son[u]=0; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(v==fa[u]) continue; fa[v]=u; dfs1(v,dep+1); if(siz[v]>siz[son[u]]) son[u]=v; siz[u]+=siz[v]; } } void dfs2(int u,int tp){ top[u]=tp; id[u]=++tot,fp[id[u]]=u; if(son[u]!=0) dfs2(son[u],tp); for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); } } void pushup(int rt){ if(maxv[rt<<1]>=maxv[rt<<1|1]){ maxv[rt]=maxv[rt<<1]; num[rt]=num[rt<<1]; } else{ maxv[rt]=maxv[rt<<1|1]; num[rt]=num[rt<<1|1]; } } void build(int l,int r,int rt){ if(l==r){ maxv[rt]=0; num[rt]=l; return ; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt); } void update(int l,int r,int rt){ if(l==p&&r==p){ maxv[rt]+=v; return ; } int m=(l+r)>>1; if(p<=m) update(lson); else update(rson); pushup(rt); } vector<int>avec[maxn]; vector<int>dvec[maxn]; void Update(int u,int v,int z){ int f1=top[u],f2=top[v]; while(f1!=f2){ if(deep[f1]<deep[f2]){ swap(f1,f2); swap(u,v); } avec[id[f1]].push_back(z); dvec[id[u]+1].push_back(z); u=fa[f1],f1=top[u]; } if(deep[u]>deep[v]){ swap(u,v); } avec[id[u]].push_back(z); dvec[id[v]+1].push_back(z); } void init(int n){ for(int i=1;i<=n;i++) G[i].clear(); mem0(maxv); mem0(son); tot=0; } int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ if(n==0&&m==0) break; init(n); int u,z; for(int i=1;i<n;i++){ scanf(u); scanf(v); G[u].push_back(v); G[v].push_back(u); } fa[1]=0,siz[0]=0; dfs1(1,0); dfs2(1,0); for(int i=1;i<=100007;i++){ avec[i].clear(); dvec[i].clear(); } build(1,100010,1); for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&z); Update(u,v,z); } for(int i=1;i<=tot;i++){ for(int j=0;j<avec[i].size();j++){ p=avec[i][j],v=1; update(1,100010,1); } for(int j=0;j<dvec[i].size();j++){ p=dvec[i][j],v=-1; update(1,100010,1); } u=fp[i]; if(maxv[1]==0) ans[u]=0; else ans[u]=num[1]; } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); } return 0; }