• POJ3237 Tree 树链剖分 线段树


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - POJ3237


    题意概括

    Description

    给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
    CHANGE i v:将第i条边的权值改成v。
    NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
    QUERY a b:找出点a到点b路径上各边的最大权值。

    Input
    多组数据,数据为T<=20,对于每组数据:
    第一行有一个整数N(N<=10000)。
    接下来N-1行每行有三个整数a,b,c,代表点a和点b之间有一条权值为c的边。这些边按照其编号从小到大给出。
    接下来是若干条指令(不超过10^5条),都按照上面所说的格式。
    最后一行是"DONE".

    Output
    对每个“QUERY”指令,输出一行,即路径上各边的最大权值。

    Sample Input
    1
    3
    1 2 1
    2 3 2
    QUERY 1 2
    CHANGE 1 3
    QUERY 1 2
    DONE

    Sample Output
    1
    3


    题解

      树链剖分+线段树单点修改、区间修改、区间询问。

      对于取相反数的,我们只需要维护一个最大值,一个最小值,然后打一下懒标记就可以了。

      在下传的时候,最大值反一反一定是最小的,最小值反一反一定是最大的,然后就好办了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    const int N=10005;
    struct Edge{
    	int cnt,y[N*2],z[N*2],nxt[N*2],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,int c){
    		y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    struct edge{
    	int a,b,c;
    }e[N];
    int T,n,fa[N],size[N],fadis[N],depth[N],son[N],top[N],p[N],ap[N],cnp;
    struct Tree{
    	int ma,mi,add;
    }t[N*4];
    void Get_Gen_Info(int rt,int pre,int d){
    	depth[rt]=d,fa[rt]=pre,size[rt]=1,son[rt]=-1;
    	for (int i=g.fst[rt];i;i=g.nxt[i])
    		if (g.y[i]!=pre){
    			int s=g.y[i];
    			Get_Gen_Info(s,rt,d+1);
    			fadis[s]=g.z[i];
    			size[rt]+=size[s];
    			if (son[rt]==-1||size[s]>size[son[rt]])
    				son[rt]=s;
    		}
    }
    void Get_Pos(int rt,int tp){
    	top[rt]=tp,p[rt]=++cnp,ap[cnp]=rt;
    	if (son[rt]==-1)
    		return;
    	else
    		Get_Pos(son[rt],tp);
    	for (int i=g.fst[rt];i;i=g.nxt[i]){
    		int s=g.y[i];
    		if (s!=fa[rt]&&s!=son[rt])
    			Get_Pos(s,s);
    	}
    }
    void pushup(int rt){
    	int ls=rt<<1,rs=ls|1;
    	t[rt].mi=min(t[ls].mi,t[rs].mi);
    	t[rt].ma=max(t[ls].ma,t[rs].ma);
    }
    void build(int rt,int le,int ri){
    	t[rt].add=0;
    	if (le==ri){
    		t[rt].ma=t[rt].mi=fadis[ap[le]];
    		return;
    	}
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,le,mid);
    	build(rs,mid+1,ri);
    	pushup(rt);
    }
    void fz(int &x,int &y){
    	x=-x,y=-y;
    	swap(x,y);
    }
    void pushdown(int rt){
    	int &a=t[rt].add;
    	int ls=rt<<1,rs=ls|1;
    	if (a==0)
    		return;
    	t[ls].add^=1,t[rs].add^=1;
    	fz(t[ls].ma,t[ls].mi);
    	fz(t[rs].ma,t[rs].mi);
    	a=0;
    }
    void change(int rt,int le,int ri,int pos,int v){
    	if (le==ri){
    		t[rt].mi=t[rt].ma=v;
    		return;
    	}
    	pushdown(rt);
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	if (pos<=mid)
    		change(ls,le,mid,pos,v);
    	else
    		change(rs,mid+1,ri,pos,v);
    	pushup(rt);
    }
    void update(int rt,int le,int ri,int xle,int xri){
    	if (le>xri||ri<xle)
    		return;
    	if (xle<=le&&ri<=xri){
    		t[rt].add^=1;
    		fz(t[rt].ma,t[rt].mi);
    		return;
    	}
    	pushdown(rt);
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	update(ls,le,mid,xle,xri);
    	update(rs,mid+1,ri,xle,xri);
    	pushup(rt);
    }
    int query(int rt,int le,int ri,int xle,int xri){
    	if (le>xri||ri<xle)
    		return -1e9;
    	if (xle<=le&&ri<=xri)
    		return t[rt].ma;
    	pushdown(rt);
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	return max(query(ls,le,mid,xle,xri),query(rs,mid+1,ri,xle,xri));
    }
    void fupdate(int a,int b){
    	int f1=top[a],f2=top[b];
    	while (f1!=f2){
    		if (depth[f1]<depth[f2])
    			swap(f1,f2),swap(a,b);
    		update(1,1,n,p[f1],p[a]);
    		a=fa[f1],f1=top[a];
    	}
    	if (a==b)
    		return;
    	if (depth[a]>depth[b])
    		swap(a,b);
    	update(1,1,n,p[son[a]],p[b]);
    }
    int find(int a,int b){
    	int f1=top[a],f2=top[b],ans=-1e9;
    	while (f1!=f2){
    		if (depth[f1]<depth[f2])
    			swap(f1,f2),swap(a,b);
    		ans=max(ans,query(1,1,n,p[f1],p[a]));
    		a=fa[f1],f1=top[a];
    	}
    	if (a==b)
    		return ans;
    	if (depth[a]>depth[b])
    		swap(a,b);
    	return max(ans,query(1,1,n,p[son[a]],p[b]));
    }
    int main(){
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d",&n);
    		g.clear();
    		for (int i=1,a,b,c;i<n;i++){
    			scanf("%d%d%d",&a,&b,&c);
    			g.add(a,b,c);
    			g.add(b,a,c);
    			e[i].a=a,e[i].b=b,e[i].c=c;
    		}
    		cnp=0,fadis[1]=0;
    		Get_Gen_Info(1,0,0);
    		Get_Pos(1,1);
    		build(1,1,n);
    		for (int i=1;i<n;i++)
    			if (depth[e[i].a]>depth[e[i].b])
    				swap(e[i].a,e[i].b);
    		char str[10];
    		int a,b;
    		while (scanf("%s",str)&&str[0]!='D'){
    			scanf("%d%d",&a,&b);
    			if (str[0]=='C')
    				change(1,1,n,p[e[a].b],b);
    			else if (str[0]=='N')
    				fupdate(a,b);
    			else
    				printf("%d
    ",find(a,b));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    编程微刊第八期文章汇总(2018.8)
    vue踩坑-This dependency was not found
    vue踩坑-This dependency was not found
    百度地图API的使用示例
    详解如何在vue项目中引入饿了么elementUI组件
    vue踩坑- 报错npm ERR! cb() never called!
    2018年九个很受欢迎的vue前端UI框架
    vue踩坑-Error: listen EADDRNOTAVAIL 192.168.1.122:8081
    详解如何在vue项目中引入饿了么elementUI组件
    js学习总结----使用setTimeout实现轮循动画
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/POJ3237.html
Copyright © 2020-2023  润新知