zoukankan      html  css  js  c++  java
  • 洛谷模拟赛 部落冲突

    题目背景

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

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

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

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

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

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

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

    题目描述

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

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

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

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

    输入输出格式

    输入格式:

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

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

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

    输出格式:

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

    输入输出样例

    输入样例#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

    这题是树链剖分的模板题

    但会卡常数,只有90分

    所以这里用树状数组维护差分

    首先按轻重链dfs序编号in[x]和out[x]

    一个点的子树范围为in[x]~out[x]

    对于一个点值为1表示与父亲是否连通,前缀和c[x]就表示他到根有多少路连通

    开始每一个点都是1如果c[p]+c[q]-2*c[lca]==dep[p]+dep[q]-2*dep[lca]就输出yes

    如果要把一个点与父亲的边赋为0,那么给in[x]~out[x]的前缀和-1就行了

    赋为1同理

    于是用小常数的树状数组就可以AC

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 using namespace std;
      6 struct Node
      7 {
      8   int next,to;
      9 }edge[600001];
     10 int head[300001],num,c[600001],in[300001],out[300001],tot,cnt,n,m;
     11 int Q[300001],dep[300001],size[300001],son[300001],top[300001],fa[300001];
     12 void build(int u,int v)
     13 {
     14   num++;
     15   edge[num].next=head[u];
     16   edge[num].to=v;
     17   head[u]=num;
     18 }
     19 void dfs1(int x,int pa)
     20 {int i;
     21   size[x]=1;
     22   dep[x]=dep[pa]+1;
     23   fa[x]=pa;
     24   int maxsize=0;
     25   for (i=head[x];i;i=edge[i].next)
     26     {
     27       int v=edge[i].to;
     28       if (v!=pa)
     29     {
     30       dfs1(v,x);
     31       size[x]+=size[v];
     32       if (size[v]>maxsize)
     33         {
     34           son[x]=v;
     35           maxsize=size[v];
     36         }
     37     }
     38     }
     39 }
     40 void dfs2(int x,int pa,int tp)
     41 {int i;
     42   in[x]=++tot;
     43   top[x]=tp;
     44   if (son[x]) dfs2(son[x],x,tp);
     45   for (i=head[x];i;i=edge[i].next)
     46     {
     47       int v=edge[i].to;
     48       if (v!=pa&&v!=son[x]) dfs2(v,x,v);
     49     }
     50   out[x]=++tot;
     51 }
     52 void add(int x,int d)
     53 {int i;
     54   for (i=x;i<=tot;i+=(i&(-i)))
     55     c[i]+=d;
     56 }
     57 int query(int x)
     58 {int i;
     59   int s=0;
     60   for (i=x;i;i-=(i&(-i)))
     61     s+=c[i];
     62   return s;
     63 }
     64 int LCA(int x,int y)
     65 {
     66   while (top[x]!=top[y])
     67     {
     68       if (dep[top[x]]<dep[top[y]]) swap(x,y);
     69       x=fa[top[x]];
     70     }
     71   if (dep[x]<dep[y]) return x;
     72   else return y; 
     73 }
     74 int main()
     75 {int i,u,v,p,q;
     76   char s[101];
     77   cin>>n>>m;
     78   for (i=1;i<=n-1;i++)
     79     {
     80       scanf("%d%d",&u,&v);
     81       build(u,v);
     82       build(v,u);
     83     }
     84   dfs1(1,0);
     85   dfs2(1,0,1);
     86   for (i=1;i<=n;i++)
     87     {
     88       add(in[i],1);
     89       add(out[i],-1);
     90     }
     91   for (i=1;i<=m;i++)
     92     {
     93       scanf("%s",s);
     94       if (s[0]=='Q')
     95     {
     96       scanf("%d%d",&p,&q);
     97       int lca=LCA(p,q);
     98       int t1=dep[p]+dep[q]-2*dep[lca];
     99       int t2=query(in[p])+query(in[q])-2*query(in[lca]);
    100       if (t1==t2)
    101         printf("Yes
    ");
    102       else printf("No
    ");
    103     }
    104       else if (s[0]=='C')
    105     {
    106       scanf("%d%d",&p,&q);
    107       if (dep[p]<dep[q]) swap(p,q);
    108       Q[++cnt]=p;
    109       add(in[p],-1);
    110       add(out[p],1);
    111     } 
    112       else if (s[0]=='U')
    113     {
    114       scanf("%d",&p);
    115       p=Q[p];
    116       add(in[p],1);
    117       add(out[p],-1);
    118     }
    119     }
    120 }
  • 相关阅读:
    Kafka常用操作备忘
    Spark执行流程(转)
    Spark性能优化总结
    Kafka学习笔记
    vue-简单例子初始化
    解析字符串模板函数
    js的apply 和 call区别
    水平垂直居中
    IE8 div旋转 Matrix,模拟轮播前后翻页按钮
    jsp 自定义标签-SimpleTagSupport 使用笔记
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7750994.html
Copyright © 2011-2022 走看看