• zjoi 2007 hide 捉迷藏 动态树分治


    题意:捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达。 游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。


    思路:动态的树的分治


      1 #include<iostream>
    2 #include<cmath>
    3 #include<cstdio>
    4 #include<cstring>
    5 #include<algorithm>
    6 #include<queue>
    7 using namespace std;
    8 #define NMAX 100010
    9 struct node
    10 {
    11 int num;
    12 node *next;
    13 };
    14 struct tree
    15 {
    16 int num,d;
    17 bool w;
    18 tree *next;
    19 };
    20 pair<int,int>child[NMAX*2];
    21 priority_queue<int> Q[NMAX][2];
    22 priority_queue<int> del[NMAX][2];
    23 node *graph[NMAX];
    24 tree *belong[NMAX];
    25 tree memo_belong[50*NMAX];
    26 node memo[2*NMAX];
    27 bool color[NMAX];
    28 int size[NMAX],label;
    29 int f[NMAX],white_sum;
    30 int n,m,top,root,ans[NMAX*2];
    31 int sumsize,minsize;
    32 void add(int x,int y)
    33 {
    34 node *p=&memo[top++];
    35 p->num=y; p->next=graph[x]; graph[x]=p;
    36 p=&memo[top++];
    37 p->num=x; p->next=graph[y]; graph[y]=p;
    38 }
    39 void add_tree(int x,bool y,int d,int L)
    40 {
    41 tree *p=&memo_belong[top++];
    42 p->num=L; p->w=y; p->next=belong[x]; p->d=d; belong[x]=p;
    43 }
    44 void get_root(int i,int fa)
    45 {
    46 int big=-1;
    47 size[i]=1;
    48 for(node *p=graph[i];p;p=p->next)
    49 if(p->num!=fa)
    50 {
    51 get_root(p->num,i);
    52 size[i]+=size[p->num];
    53 if(size[p->num]>big) big=size[p->num];
    54 }
    55 if(sumsize-size[i]>big) big=sumsize-size[i];
    56 if(big<minsize) minsize=big,root=i;
    57 }
    58 void dfs2(int i,int d,bool w,int fa,int L)
    59 {
    60 add_tree(i,w,d,L);
    61 Q[L][w].push(d);
    62 for(node *p=graph[i];p;p=p->next)
    63 if(p->num!=fa)
    64 dfs2(p->num,d+1,w,i,L);
    65 }
    66 void calc(int L)
    67 {
    68 ans[L]=max(ans[child[L].first],ans[child[L].second]);
    69 if(!Q[L][0].empty()&&!Q[L][1].empty())
    70 ans[L]=max(ans[L],Q[L][0].top()+Q[L][1].top());
    71 }
    72 int dfs(int i,int size_i)
    73 {
    74 if(size_i<=2) return 0;
    75 sumsize=minsize=size_i;
    76 get_root(i,-1); i=root;
    77 get_root(i,-1);
    78 ++label;
    79 int L=label;
    80 node *mid,*mid_next,*p,*left=graph[i];
    81 int sum=0;
    82 for(p=graph[i];p->next!=NULL;p=p->next)
    83 {
    84 sum+=size[p->num];
    85 if(sum>=(size_i-1)/2||p->next->next==NULL) break;
    86 }
    87 mid=p;
    88 mid_next=mid->next; mid->next=NULL;
    89 dfs2(i,0,0,-1,L);
    90 child[L].first=dfs(i,sum+1);
    91 mid->next=mid_next; graph[i]=mid_next;
    92 dfs2(i,0,1,-1,L);
    93 child[L].second=dfs(i,size_i-sum);
    94 calc(L);
    95 return L;
    96 }
    97 void update(int x)
    98 {
    99 tree *t;
    100 int label,d,w;
    101 for(t=belong[x];t;t=t->next)
    102 {
    103 label=t->num; d=t->d; w=t->w;
    104 if(color[x]==1)
    105 del[label][w].push(d);
    106 else Q[label][w].push(d);
    107 while(!del[label][w].empty()&&Q[label][w].top()==del[label][w].top())
    108 {
    109 Q[label][w].pop(); del[label][w].pop();
    110 }
    111 calc(label);
    112 }
    113 }
    114
    115 int main()
    116 {
    117 freopen("hide.in","r",stdin);
    118 freopen("hide.out","w",stdout);
    119 ans[0]=-1;
    120 int i,j;
    121 char c[10];
    122 int x,y,z;
    123 scanf("%d",&n);
    124 label=top=0;
    125 memset(color,0,sizeof(color));
    126 memset(belong,0,sizeof(belong));
    127 memset(graph,0,sizeof(graph));
    128 for(i=1;i<n;i++)
    129 {
    130 scanf("%d%d",&x,&y);
    131 add(x,y);
    132 }
    133 top=0; white_sum=size[1]=n;
    134 dfs(1,n);
    135 scanf("%d",&m);
    136 for(i=1;i<=m;i++)
    137 {
    138 scanf("%s",c);
    139 if(c[0]=='C')
    140 {
    141 scanf("%d",&x);
    142 if(color[x]==0) white_sum--;
    143 else white_sum++;
    144 color[x]=!color[x];
    145 update(x);
    146 }
    147 else
    148 {
    149 if(white_sum==0) printf("-1\n");
    150 else if (white_sum==1) printf("0\n");
    151 else printf("%d\n",ans[1]);
    152 }
    153 }
    154 return 0;
    155 }



  • 相关阅读:
    EditPlus v2.12 使用技巧集萃
    GridView列数字、货币和日期的显示格式
    使用模态窗口编辑数据
    求sql查询语句(转换数据表由纵向转换成横向)
    插入数据 存储过程生成帐单号
    65个源代码网站
    C#抓屏(截屏)
    SQL中SET NOCOUNT的用法
    在Visual Studio2005 中调试JavaScript
    WinForm下App.config配置文件的读与写
  • 原文地址:https://www.cnblogs.com/myoi/p/2415638.html
Copyright © 2020-2023  润新知