JZOJ 5463. 【NOIP2017提高A组冲刺11.8】证书
2017-11-08 22:38
387 查看
Description
Pulumi生活在P城的角落,而他的朋友们gjdy,oyski,tutuwai等等生活在P城的靠中心位置。P城很大,但它拥有优秀的城市结构,同时P城重视文化教育的发展,P城共有n个学校,校与校之间共建立了n-1条交通线路,且两所学校之间存在唯一的连通路径。
P城常常举行各种类型的评比活动,为了节约资金,最终将给某一条路径上的所有学校颁发证书。为了便于描述我们记一次评比活动的结果为(ui,vi,zi)表示路径(ui,vi)上的所有学校获得一个类型为zi的证书。
一个学校若为Zmax类型的学校,则表示它在Zmax类型下的证书数量最多(如果有相同数量的类型,取类型标号最小一个)。
Pulumi收集了本年度所有的评比活动结果,共m次。他很感兴趣所有学校的类型,以了解他朋友们学校的状况,现在他忙于出题,把这个任务交给了你。
Input
第一行,两个整数n,m,如题中所述。下接n-1行,每行两个整数u,v,表示标号u和v的学校之间有一条直接相连的路。
下接m行,每行三个整数u,v,z,表示一次结果为(u,v,z)的评比活动。
Output
共n行,第i行,一个整数zi,表示标号为i的学校类型为zi。Sample Input
5 31 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
Sample Output
23
3
0
2
Data Constraint
对于30%的数据1<=N<=1000,1<=M<=1000另外在30%的数据满足i-1与i之间有一条直接相连的路
对于100%的数据1<=N<=100000,0<=M<=100000,1<=zi<=10^9
Solution
看到这题,区间操作操作又在树上,那么就想到树链剖分+线段树。在每条链链头打一个加标记,在链尾的后一位打一个减标记。
这样得到的DFS序上就有了很多标记,我们直接在序列上查找、修改即可。
每到一个点,就进行在这个点上的操作,之后查询最大值的位置。
注意 zi 的值很大,需要进行离散化。
Code
#include<cstdio> #include<algorithm> #include<vector> using namespace std; const int N=1e5+1; struct data { int x,y; }f[N<<2]; int tot,num; int first ,next[N<<1],en[N<<1]; int fa ,size ,dep ; int son ,tree ,pre ,top ; int h ,id ,p ,ans ,a ,b ,c ; vector<int>g ; inline int read() { int X=0,w=1; char ch=0; while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar(); return X*w; } inline void write(int x) { if(x>9) write(x/10); putchar(x%10+'0'); } inline void insert(int x,int y) { next[++tot]=first[x]; first[x]=tot; en[tot]=y; } inline void dfs1(int x) { dep[x]=dep[fa[x]]+1,size[x]=1; for(int i=first[x];i;i=next[i]) if(en[i]^fa[x]) { fa[en[i]]=x; dfs1(en[i]); size[x]+=size[en[i]]; if(!son[x] || size[en[i]]>size[son[x]]) son[x]=en[i]; } } inline void dfs2(int x,int y) { top[pre[tree[x]=++num]=x]=y; if(!son[x]) return; dfs2(son[x],y); for(int i=first[x];i;i=next[i]) if(en[i]^fa[x] && en[i]^son[x]) dfs2(en[i],en[i]); } inline data merge(data x,data y) { return x.x>=y.x?x:y; } inline void change(int v,int l,int r,int x,int y) { if(l==r) { if(f[v].x+=y) f[v].y=x; else f[v].y=0; return; } int mid=(l+r)>>1; if(x<=mid) change(v<<1,l,mid,x,y); else change(v<<1|1,mid+1,r,x,y); f[v]=merge(f[v<<1],f[v<<1|1]); } inline data find(int v,int l,int r,int x,int y) { if(l>=x && r<=y) return f[v]; int mid=(l+r)>>1; if(y<=mid) return find(v<<1,l,mid,x,y); if(x>mid) return find(v<<1|1,mid+1,r,x,y); return merge(find(v<<1,l,mid,x,mid),find(v<<1,mid+1,r,mid+1,y)); } int main() { int n=read(),m=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); insert(x,y); insert(y,x); } dfs1(1),dfs2(1,1); for(int i=1;i<=m;i++) { a[i]=read(),b[i]=read(),c[i]=read(); h[++h[0]]=c[i]; } sort(h+1,h+1+h[0]); id[1]=tot=1,p[1]=h[1]; for(int i=2;i<=h[0];i++) if(h[i]^h[i-1]) p[id[i]=++tot]=h[i]; else id[i]=id[i-1]; for(int i=1;i<=m;i++) { int x=a[i],y=b[i],z=c[i]; int k=lower_bound(h+1,h+1+h[0],z)-h; z=id[k]; int f1=top[x],f2=top[y]; while(f1^f2) { if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y); g[tree[f1]].push_back(z); g[tree[x]+1].push_back(-z); x=fa[f1],f1=top[x]; } if(dep[x]>dep[y]) swap(x,y); g[tree[x]].push_back(z); g[tree[y]+1].push_back(-z); } for(int i=1;i<=num;i++) { for(int j=0;j<g[i].size();j++) { int x=abs(g[i][j]),y=g[i][j]>0?1:-1; change(1,1,tot,x,y); } data t=find(1,1,tot,1,tot); ans[pre[i]]=p[t.y]; } for(int i=1;i<=n;i++) write(ans[i]),putchar('\n'); return 0; }
相关文章推荐
- JZOJ5463. 【NOIP2017提高A组冲刺11.8】证书
- jzoj5463 【NOIP2017提高A组冲刺11.8】证书
- [jzoj5462]【NOIP2017提高A组冲刺11.8】好文章
- 【JZOJ 5461】【NOIP2017提高A组冲刺11.8】购物
- jzoj5463【NOIP2017提高A组冲刺11.8】证书
- JZOJ5461. 【NOIP2017提高A组冲刺11.8】购物
- JZOJ5462. 【NOIP2017提高A组冲刺11.8】好文章
- JZOJ 5462. 【NOIP2017提高A组冲刺11.8】好文章
- [JZOJ5456]【NOIP2017提高A组冲刺11.6】奇怪的队列
- JZOJ5455. 【NOIP2017提高A组冲刺11.6】拆网线
- JZOJ 5442. 【NOIP2017提高A组冲刺11.1】荒诞
- [JZOJ5451]【NOIP2017提高A组冲刺11.4】Genocide
- JZOJ 5440. 【NOIP2017提高A组冲刺11.1】背包
- JZOJ5461. 【NOIP2017提高A组冲刺11.8】购物 贪心+堆
- Jzoj5440 【NOIP2017提高A组冲刺11.1】背包
- JZOJ5440. 【NOIP2017提高A组冲刺11.1】背包
- JZOJ5442. 【NOIP2017提高A组冲刺11.1】荒诞
- JZOJ 5466. 【NOIP2017提高A组冲刺11.9】玩游戏
- [JZOJ5457]【NOIP2017提高A组冲刺11.6】项链
- JZOJ5453. 【NOIP2017提高A组冲刺11.5】好路线