zoukankan      html  css  js  c++  java
  • BZOJ 3531 SDOI2014 旅行 树链剖分

    题目大意:给定一棵树,每一个点有一个权值和一个颜色。多次改变一些点的权值和颜色,多次求一条路径上与起点和终点颜色同样的点的权值和以及权值最大值

    每种颜色开一个线段树 动态开节点 每一个点仅仅建一条链 这样空间复杂度是O(nlogn)的

    然后就正常树链剖分即可了

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define M 100100
    using namespace std;
    struct abcd{
    	int to,next;
    }table[M<<1];
    struct Segtree{
    	Segtree *ls,*rs;
    	int sum,max_num;
    	Segtree():ls(0x0),rs(0x0),sum(0),max_num(0){}
    }*tree[M];
    int head[M],tot;
    int n,m;
    int w[M],c[M];
    int fa[M],son[M],dpt[M],size[M],pos[M],top[M],cnt;
    void Update(Segtree* &p,int x,int y,int z,int v)
    {
    	int mid=x+y>>1;
    	if(!p) p=new Segtree;
    	if(x==y)
    	{
    		p->sum=p->max_num=v;
    		return ;
    	}
    	if(z<=mid) Update(p->ls,x,mid,z,v);
    	else       Update(p->rs,mid+1,y,z,v);
    	p->sum=(p->ls?p->ls->sum:0)+(p->rs?p->rs->sum:0);
    	p->max_num=max( (p->ls?p->ls->max_num:0) , (p->rs?

    p->rs->max_num:0) ); } int Get_Sum(Segtree *p,int x,int y,int l,int r) { int mid=x+y>>1; if(!p) return 0; if(x==l&&y==r) return p->sum; if(r<=mid) return Get_Sum(p->ls,x,mid,l,r); if(l>mid) return Get_Sum(p->rs,mid+1,y,l,r); return Get_Sum(p->ls,x,mid,l,mid) + Get_Sum(p->rs,mid+1,y,mid+1,r); } int Get_Max(Segtree *p,int x,int y,int l,int r) { int mid=x+y>>1; if(!p) return 0; if(x==l&&y==r) return p->max_num; if(r<=mid) return Get_Max(p->ls,x,mid,l,r); if(l>mid) return Get_Max(p->rs,mid+1,y,l,r); return max( Get_Max(p->ls,x,mid,l,mid) , Get_Max(p->rs,mid+1,y,mid+1,r) ); } void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void DFS1(int x) { int i; dpt[x]=dpt[fa[x]]+1; size[x]=1; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x]) continue; fa[table[i].to]=x; DFS1(table[i].to); size[x]+=size[table[i].to]; if(size[table[i].to]>size[son[x]]) son[x]=table[i].to; } } void DFS2(int x) { int i; pos[x]=++cnt; if(son[fa[x]]==x) top[x]=top[fa[x]]; else top[x]=x; Update(tree[c[x]],1,n,pos[x],w[x]); if(son[x]) DFS2(son[x]); for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x]||table[i].to==son[x]) continue; DFS2(table[i].to); } } int Query_Sum(int x,int y,int _c) { int fx=top[x],fy=top[y],re=0; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy); re+=Get_Sum(tree[_c],1,n,pos[fx],pos[x]); x=fa[fx];fx=top[x]; } if(dpt[x]<dpt[y]) swap(x,y); re+=Get_Sum(tree[_c],1,n,pos[y],pos[x]); return re; } int Query_Max(int x,int y,int _c) { int fx=top[x],fy=top[y],re=0; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy); re=max(re,Get_Max(tree[_c],1,n,pos[fx],pos[x])); x=fa[fx];fx=top[x]; } if(dpt[x]<dpt[y]) swap(x,y); re=max(re,Get_Max(tree[_c],1,n,pos[y],pos[x])); return re; } int main() { int i,x,y; char p[10]; cin>>n>>m; for(i=1;i<=n;i++) scanf("%d%d",&w[i],&c[i]); for(i=1;i<n;i++) scanf("%d%d",&x,&y),Add(x,y),Add(y,x); DFS1(1);DFS2(1); for(i=1;i<=m;i++) { scanf("%s%d%d",p,&x,&y); switch(p[1]) { case 'C': Update(tree[c[x]],1,n,pos[x],0); Update(tree[c[x]=y],1,n,pos[x],w[x]); break; case 'W': Update(tree[c[x]],1,n,pos[x],w[x]=y); break; case 'S': printf("%d ", Query_Sum(x,y,c[x]) ); break; case 'M': printf("%d ", Query_Max(x,y,c[x]) ); break; } } }



  • 相关阅读:
    Yii常用路径说明
    PHP-redis中文文档
    PHP 判断客户端是IOS还是Android
    yiii 框架登录 判断是否是游客模式及未登录状态
    php实现数字格式化,数字每三位加逗号的功能函数
    php array_udiff_uassoc比较数组的键值与值
    php--数组函数array
    安装Postman
    vue指令
    vue 错误记录
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7151729.html
Copyright © 2011-2022 走看看