[bzoj3307]雨天的尾巴
来源:互联网 发布:突破阶级的途径 知乎 编辑:程序博客网 时间:2024/04/25 03:08
题目大意
有m个操作每次将树上一条路径每个结点出扔一个物品。
最后需要输出每个结点上最多的物品的种类。
优美算法
树链剖分两个log,但是本题可以一个log算法。
每个操作对应一条路径也就是一条线段。
一个结点x所有的物品要么是从其子树里延伸出的线段,要么是以其为端点的线段。
那么每个结点维护线段树表示每个物品的出现次数。
每个操作都拆成三个操作两个插入操作挂在端点上一个删除操作挂在lca上。
然后子树信息只要打线段树合并即可。
完美n log n。
然而我疑惑的一点和Po姐一样——这个算法为何比树剖慢。
#include<cstdio>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=100000+10;struct dong{ int x,y,z;};dong a[maxn];int h[maxn],go[maxn*2],next[maxn*2];int h2[maxn],g2[maxn*3],n2[maxn*3],root[maxn],ans[maxn];bool bz[maxn*3];int b[maxn],d[maxn],f[maxn][20],tree[maxn*40],left[maxn*40],right[maxn*40];int i,j,k,l,t,n,m,tot,top;void add(int x,int y){ go[++tot]=y; next[tot]=h[x]; h[x]=tot;}void add2(int x,int y,bool z){ g2[++tot]=y; bz[tot]=z; n2[tot]=h2[x]; h2[x]=tot;}void dfs(int x,int y){ d[x]=d[y]+1; f[x][0]=y; int t=h[x]; while (t){ if (go[t]!=y) dfs(go[t],x); t=next[t]; }}int lca(int x,int y){ int j; if (d[x]<d[y]) swap(x,y); if (d[x]!=d[y]){ j=floor(log(n)/log(2)); while (j>=0){ if (d[f[x][j]]>d[y]) x=f[x][j]; j--; } x=f[x][0]; } if (x==y) return x; j=floor(log(n)/log(2)); while (j>=0){ if (f[x][j]!=f[y][j]){ x=f[x][j]; y=f[y][j]; } j--; } return f[x][0];}int merge(int x,int y,int l,int r){ if (!x||!y) return x+y; if (l==r){ tree[x]+=tree[y]; return x; } int mid=(l+r)/2; left[x]=merge(left[x],left[y],l,mid); right[x]=merge(right[x],right[y],mid+1,r); tree[x]=max(tree[left[x]],tree[right[x]]); return x;}void insert(int &x,int l,int r,int a,int b){ if (!x) x=++tot; if (l==r){ tree[x]+=b; return; } int mid=(l+r)/2; if (a<=mid) insert(left[x],l,mid,a,b);else insert(right[x],mid+1,r,a,b); tree[x]=max(tree[left[x]],tree[right[x]]);}int find(int x,int l,int r){ if (l==r) return l; int mid=(l+r)/2; if (tree[x]==tree[left[x]]) return find(left[x],l,mid);else return find(right[x],mid+1,r);}void solve(int x,int y){ int t=h[x]; while (t){ if (go[t]!=y){ solve(go[t],x); root[x]=merge(root[x],root[go[t]],1,top); } t=next[t]; } t=h2[x]; while (t){ if (bz[t]) insert(root[x],1,top,g2[t],1); else insert(root[x],1,top,g2[t],-1); t=n2[t]; } ans[x]=tree[root[x]]?b[find(root[x],1,top)]:0; t=h2[x]; while (t){ if (!bz[t]) insert(root[x],1,top,g2[t],-1); t=n2[t]; }}int read(){ int x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x;}int main(){ freopen("t3.in","r",stdin);freopen("t3.out","w",stdout); n=read();m=read(); fo(i,1,n-1){ j=read();k=read(); add(j,k);add(k,j); } tot=0; dfs(1,0); fo(j,1,floor(log(n)/log(2))) fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1]; fo(i,1,m) a[i].x=read(),a[i].y=read(),a[i].z=b[i]=read(); sort(b+1,b+m+1); top=unique(b+1,b+m+1)-b-1; fo(i,1,m) a[i].z=lower_bound(b+1,b+top+1,a[i].z)-b; fo(i,1,m){ add2(a[i].x,a[i].z,1); add2(a[i].y,a[i].z,1); add2(lca(a[i].x,a[i].y),a[i].z,0); } tot=0; solve(1,0); fo(i,1,n) printf("%d\n",ans[i]);}
0 0
- bzoj3307 雨天的尾巴
- [bzoj3307]雨天的尾巴
- BZOJ3307: 雨天的尾巴
- 【bzoj3307】雨天的尾巴 线段树+树链剖分
- BZOJ3307——雨天的尾巴
- [BZOJ3307][线段树合并]雨天的尾巴
- [BZOJ3307][雨天的尾巴][树链剖分+线段树]
- 【BZOJ3307】雨天的尾巴(权限题)
- bzoj3307雨天的尾巴(线段树合并)
- BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
- 【BZOJ3307】雨天的尾巴(树链剖分+树上差分+线段树)
- 雨天的尾巴
- [JZOJ3397]雨天的尾巴
- 雨天的尾巴
- 【JZOJ3397】雨天的尾巴
- bzoj-3307 雨天的尾巴
- bzoj 3307: 雨天的尾巴
- 【JZOJ 3397】 雨天的尾巴
- Java线程创建的三种方式
- 点击效果实现的多种方法
- Zookeeper四字命令
- poj-1321-棋盘问题
- Python Tricks(九)—— 递归遍历目录下所有文件
- [bzoj3307]雨天的尾巴
- cocos2d-x 的安装以及hello world
- 视频图像处理基础知识4(视频分辨率参考 行频 隔行扫描 逐行扫描)
- String.getBytes()
- Spark on YARN集群模式作业运行全过程分析
- JSP+Serverlet+javaScript+ajax实现实时检测用户名是否被占用
- 《Linux命令行与shell脚本》笔记--第1章:初识linux shell
- 数据结构--线性表的链式表示与实现
- 11059 - Maximum Product