雨天的尾巴
来源:互联网 发布:百分百营销软件站 编辑:程序博客网 时间:2024/04/26 01:23
题目大意
给定一棵n个点的树。有m个操作,每个操作给出x,y,z,然后对于点x 到点y 的路径上(含x 和y) 每个点对应数值为z的数的个数+1。
最后输出每个点个数最多的数的数值(个数相同输出数值较小值)。
数据范围 n,m <= 100000,z<=10^9。
树链剖分,复杂度O(nlogn2 )
(werkeytom大神用线段树合并O(n log n)解决)
z比较大,但最多也就m种,所以我们先离散化z。
首先考虑序列上的做法,对于一个操作x,y,z(离散化后的),我们拆成两个操作
1:a=x,z,b=1;2:a=y+1,z,b=-1。然后把操作按a值排序。
然后我们O(n)扫一遍每个位置,把每个位置上的操作都处理掉,每个操作为数值为z的数的个数+b,用线段树维护数值为z的数的个数,那么当前位置的答案我们可以直接得出。修改操作复杂度为O(log n),总复杂度O(n log n)。
树上的怎么做呢?我们可以树链剖分一下,每条链都是一段序列,所以我们可以把操作拆开,一个操作最多拆log n次,然后剩下的按序列上的做,总时间O(
代码
#include<cstdio>#include<algorithm>#include<cstring>#define ll long longusing namespace std;const int maxn=100000+5;int tree[maxn*4],p[maxn],tr[maxn*4],t,n,m,k[maxn],c[maxn],next[maxn*2],g[maxn*2],num,s[maxn],son[maxn],b[maxn],a[maxn],qx[maxn],qy[maxn],ans[maxn],q[maxn],fa[maxn],f[maxn],d[maxn],bz[maxn],bk[maxn],cnt[maxn*36][3];void add(int x,int y){ next[++num]=k[x]; k[x]=num; g[num]=y;}void read(int &n){ char ch=getchar(); while(ch!='-'&&(ch<'0')||(ch>'9'))ch=getchar();n=0; int q=1;if (ch=='-') ch=getchar(),q=-1; while(ch>='0'&&ch<='9')n=n*10+ch-'0',ch=getchar();n=n*q;}void dfs(int x,int y){ int i=k[x],s1=0; s[x]=1;fa[x]=y;f[x]=x; while (i>0){ if (g[i]!=y) { d[g[i]]=d[x]+1; dfs(g[i],x); s[x]+=s[g[i]]; if (s[g[i]]>s1) s1=s[g[i]],son[x]=g[i]; } i=next[i]; }}void df(int x,int y){ if (son[y]==x) f[x]=f[y]; b[x]=++num; a[num]=x; if (son[x]>0) df(son[x],x); int i=k[x]; while (i>0){ if (g[i]!=y&&son[x]!=g[i]) df(g[i],x); i=next[i]; }}void qs(int l,int r){ int i=l,j=r,m=q[(l+r)/2]; while (i<=j){ while (q[i]<m) i++; while (q[j]>m) j--; if (i<=j){ swap(q[i],q[j]); swap(qx[i],qx[j]); swap(qy[i],qy[j]); i++;j--; } } if (i<r) qs(i,r); if (l<j) qs(l,j); }void qss(int l,int r){ int i=l,j=r,m=cnt[(l+r)/2][1]; while (i<=j){ while (cnt[i][1]<m) i++; while (cnt[j][1]>m) j--; if (i<=j){ swap(cnt[i],cnt[j]); i++;j--; } } if (i<r) qss(i,r); if (l<j) qss(l,j); }void put(int k,int l,int r,int x,int y){ if (l==r) { tree[k]+=y; tr[k]=p[l]; return; } int m=(l+r)/2; if (x<=m) put(k*2,l,m,x,y);else put(k*2+1,m+1,r,x,y); if (tree[k*2]>=tree[k*2+1]) { tree[k]=tree[k*2]; tr[k]=tr[k*2]; }else{ tree[k]=tree[k*2+1]; tr[k]=tr[k*2+1]; }}int main(){ read(n);read(m);num=0; for (int i=1;i<n;i++){ int x,y;read(x);read(y); add(x,y);add(y,x); } dfs(1,0);num=0; df(1,0); for (int i=1;i<=m;i++) read(qx[i]),read(qy[i]),read(q[i]); qs(1,m);q[0]=0;t=0; for (int i=1;i<=m;i++) if (q[i]>q[i-1]) c[i]=++t,p[t]=q[i];else c[i]=t; num=0; for (int i=1;i<=m;i++){ int x=qx[i],y=qy[i]; while (f[x]!=f[y]){ if (d[f[x]]<d[f[y]]) swap(x,y); num++;cnt[num][0]=c[i]; cnt[num][1]=b[f[x]];cnt[num][2]=1; num++;cnt[num][0]=c[i]; cnt[num][1]=b[x]+1;cnt[num][2]=-1; x=fa[f[x]]; } if (d[x]<d[y]) swap(x,y); num++;cnt[num][0]=c[i]; cnt[num][1]=b[y];cnt[num][2]=1; num++;cnt[num][0]=c[i]; cnt[num][1]=b[x]+1;cnt[num][2]=-1; } qss(1,num);int j=1; for (int i=1;i<=n;i++){ while (j<=num&&cnt[j][1]==i) put(1,1,t,cnt[j][0],cnt[j][2]),j++; if (tree[1]>0)ans[a[i]]=tr[1];else ans[a[i]]=0; } for (int i=1;i<=n;i++) printf("%d\n",ans[i]);}
0 0
- bzoj3307 雨天的尾巴
- 雨天的尾巴
- [bzoj3307]雨天的尾巴
- [JZOJ3397]雨天的尾巴
- 雨天的尾巴
- 【JZOJ3397】雨天的尾巴
- BZOJ3307: 雨天的尾巴
- bzoj-3307 雨天的尾巴
- bzoj 3307: 雨天的尾巴
- 【JZOJ 3397】 雨天的尾巴
- 【JZOJ 3397】雨天的尾巴
- 【GDOI2014模拟】雨天的尾巴
- 【GDOI2014模拟】雨天的尾巴
- BZOJ 3307: 雨天的尾巴
- BZOJ 3307 雨天的尾巴 线段树
- 【bzoj3307】雨天的尾巴 线段树+树链剖分
- [JZOJ3397]【GDOI2014模拟】雨天的尾巴
- 【GDOI2014模拟】雨天的尾巴 题解+代码
- Java Concurrent包源码学习和使用心得 之 LinkedBlockingQueue源码解读
- js正则替换指定的所有字符
- 隐马尔科夫模型(HMM)——qjzcy的博客
- #NString属性修饰符号为什么用copy?
- poj1330 Nearest Common Ancestors(LCA离线算法)
- 雨天的尾巴
- _STORAGE_WRITE_ERROR_:./Runtime/Cache/Home/
- 对String 分段展示
- 多线程编程艺术(4)-线程间数据传输
- Hadoop2.2.0伪分布式搭建简述
- aop应用范围
- js输入一个日期,返回星期的数字.html
- android:paddingLeft 或者 android:paddingRight报错
- jmeter使用代理录制脚本