zoukankan      html  css  js  c++  java
  • 【luogu3950】部落冲突--树剖

    题目背景

    在一个叫做Travian的世界里,生活着各个大大小小的部落。其中最为强大的是罗马、高卢和日耳曼。他们之间为了争夺资源和土地,进行了无数次的战斗。期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事。

    其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这些部落与部落之间相连的道路看作一颗树,可见每条道路对于Travian世界的重要程度。有了这些道路,建筑工人就可以通过这些道路进行友好外交啦。

    然而,事情并不会像想象的那样美好,由于资源的匮乏,相邻的部落(由一条道路相连的部落)之间经常会发生大大小小的冲突事件,更有甚者,会升级为部落之间的大型战争。

    为了避免误伤,每当两个相邻的部落之间发生大型战争之时,这两个部落间的道路是不允许通行的,对于一些强大的部落,甚至能与多个相邻的部落同时开战,同样的,这些战争地带的道路十分危险,是不可通行的。

    天下之势,分久必合,当两个部落经历了不打不相识的苦战之后,他们可以签订停战协议(暂时停战,以后依旧可能再次开战),这样,两个部落之间的道路又会重新恢复为可通行状态,建筑工人们又可以经过此地购买最新的大本营设计图纸来强大自己的部落了。

    为了简单起见,我们把各大战争事件按发起的时间顺序依次编号(最先发起的战争编号就为 1,第二次战争编号就为 2,以此类推),当两个部落停战之时,则会直接告诉你这场战争的编号,然后这场战争就载入了史册,不复存在了,当然,这并不会影响到其他战争的编号。

    建筑工人十分讨厌战争,因为战争,想从一个部落到另一个部落进行友好交流的建筑工人可能就此白跑一趟。所以,在他们出发之前,都会向你问问能不能到达他们想去的部落。

    题目描述

    简单起见,你就是要处理下面三件事,所有的事件都是按照时间顺序给出的。

    1.Q,p,q从第 p个部落出发的建筑工人想知道能否到达第 q 个部落了,你要回答的便是(Yes/No),注意大小写

    2.(C p q)第 p 个部落与第 q 个部落开战了,保证他们一定是相邻的部落,且目前处于停战(未开战)状态

    3.U xx 次发生的战争结束了,它将永远的被载入史册,不复存在(保证这个消息不会告诉你多次)

    输入格式

    第一行两个数 nmn 代表了一共有 n 个部落,m 代表了以上三种事件发生的总数

    接下来的 n−1 行,每行两个数 p, q,代表了第 p 个部落与第 q 个部落之间有一条道路相连

    接下来的 m 行,每行表示一件事,详见题目描述

    输出格式

    每行一个“Yes”或者“No”,表示从第 ppp 个部落出发的建筑工人能否到达第 q个部落

    输入输出样例

    输入 #1
    5 9
    1 2
    2 3
    3 4
    4 5
    Q 1 4
    C 2 1
    C 4 3
    Q 3 1
    Q 1 5
    U 1
    U 2
    C 4 3
    Q 3 4
    输出 #1
    Yes
    No
    No
    No
    输入 #2
    10 10
    1 2
    1 3
    3 4
    3 5
    1 6
    3 7
    1 8
    2 9
    5 10
    C 8 1
    Q 6 1
    C 2 1
    Q 2 10
    U 1
    C 9 2
    C 7 3
    U 3
    Q 6 7
    Q 1 10
    输出 #2
    Yes
    No
    No
    Yes
    输入 #3
    20 20
    1 2
    1 3
    2 4
    1 5
    1 6
    4 7
    1 8
    2 9
    5 10
    1 11
    2 12
    7 13
    1 14
    1 15
    11 16
    4 17
    3 18
    18 19
    8 20
    Q 13 5
    C 14 1
    C 16 11
    U 1
    U 2
    C 20 8
    Q 7 1
    C 7 4
    Q 17 17
    Q 1 6
    C 16 11
    C 2 1
    Q 16 2
    U 3
    U 5
    U 6
    C 2 1
    C 6 1
    C 13 7
    C 11 1
    
    输出 #3
    Yes
    Yes
    Yes
    Yes
    No
    

    说明/提示

    对于30%的数据 1<=n,m<=6000

    对于另30%的数据,保证部落之间的地理关系是一条链,且 i 与 i + 1 之间有一条道路

    对于另30%的数据,1<=n,m<=100000

    对于100%的数据,1<=n,m<=300000

      这道题用树剖,其实就是维护区间的最大值,如果两个部落间有冲突,那么就两点间的

    边权赋成一,询问时区间最大值如果为一,则说明不连通,如果冲突解除,则赋成零

      注意边权化为点权

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #define N 1000000
    using namespace std;
    int son[N],fa[N],head[N],top[N],cnt,tot,tr[N],wt[N],val[N],dep[N],siz[N];
    int n,m,id[N];
    struct node{
    	int to,nxt,dis;
    }e[N<<1];
    struct edge {
    	int l,r;
    }a[N<<1];
    void add(int from,int to,int dis)
    {
    	e[++tot]=(node){to,head[from],dis};
    	head[from]=tot;
    }
    void dfs1(int x,int f)
    {
    	dep[x]=dep[f]+1;
    	siz[x]=1;
    	fa[x]=f;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa[x])continue;
    		val[y]=e[i].dis;
    		dfs1(y,x);
    		if(siz[y]>siz[son[x]])son[x]=y;
    	}
    }
    void dfs2(int x,int topf)
    {
    	top[x]=topf;
    	id[x]=++cnt;
    	wt[cnt]=val[x];
    	if(!son[x])return;
    	dfs2(son[x],topf);
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa[x]||y==son[x])continue;
    		dfs2(y,y);
    	}
    }
    void update(int k){
    	tr[k]=max(tr[k<<1],tr[k<<1|1]);
    }
    void build(int k,int l,int r)
    {
    	if(l==r)
    	{
    		tr[k]=wt[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	update(k);
    }
    void change(int k,int l,int r,int x,int val)
    {
    	if(l==r)
    	{
    		tr[k]=val;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid)change(k<<1,l,mid,x,val);
    	if(x>mid)change(k<<1|1,mid+1,r,x,val);
    	update(k);
    }
    int ask(int k,int l,int r,int x,int y)
    {
    	int ans=-2147483647;
    	if(x<=l && y>=r)
    	{
    		return tr[k];
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid)ans=max(ans,ask(k<<1,l,mid,x,y));
    	if(y>mid)ans=max(ans,ask(k<<1|1,mid+1,r,x,y));
    	return ans;
    }
    int query_chain(int x,int y)
    {
    	int ans=-214748364;
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		ans=max(ans,ask(1,1,n,id[top[x]],id[x]));
    		x=fa[top[x]];
    	}
    	if(dep[x]<dep[y])swap(x,y);
    	ans=max(ans,ask(1,1,n,id[y]+1,id[x]));////边权化为点权
    	return ans;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1,x,y;i<=n-1;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y,0); add(y,x,0);
    	}
    	dfs1(1,0);
    	dfs2(1,1);
    	build(1,1,n);
    	char s[10]; int tt=0;
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%s",s+1);
    		if(s[1]=='C')
    		{
    			tt++;
    			scanf("%d%d",&a[tt].l , &a[tt].r);
    			int xx;
    			if(dep[a[tt].l]<dep[a[tt].r])xx=a[tt].r;
    			else xx=a[tt].l;
    			change(1,1,n,id[xx],1);
    		}
    		if(s[1]=='U')
    		{
    			scanf("%d",&x);
    			int xx;
    			if(dep[a[x].l]<dep[a[x].r])xx=a[x].r;
    			else xx=a[x].l;
    			change(1,1,n,id[xx],0);
    		}
    		if(s[1]=='Q')
    		{
    			scanf("%d%d",&x,&y);
    			int p=query_chain(x,y);
    			if(p==1)printf("No
    ");
    			else printf("Yes
    ");
    		}
    	}
    	return 0;
    }
    /*
    5 9
    1 2
    2 3
    3 4
    4 5
    Q 1 4
    C 2 1
    C 4 3
    Q 3 1
    Q 1 5
    U 1
    U 2
    C 4 3
    Q 3 4
    */
    
  • 相关阅读:
    SqlServer存储过程函数加解密[极有用]
    BMDThread控件动态创建多线程示例
    cxGrid右键自定义菜单
    越狱中Michael的一种疾病
    静态链表
    单行编辑框SelectText()
    开机得按F1
    jquery调用页面后台方法‏
    .net调用存储过程详解
    javascript兼容各种浏览器的异步请求
  • 原文地址:https://www.cnblogs.com/yelir/p/11600301.html
Copyright © 2011-2022 走看看