Hilarity
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 461 Accepted Submission(s): 125
Problem Description
After June 1st, elementary students of Ted Land are still celebrating "The Sacred Day of Elementary Students”. They go to the streets and do some elementary students stuff. So we call them "elementary students". There are N cities in Ted Land. But for simplicity, the mayor Matt only built N - 1 roads so that all cities can reach each other. Some of the roads are occupied by the "elementary students". They will put an celebration hat on everyone who goes through the road without one. But if someone goes through the road with a celebration hat on his head, "elementary students" will steal the hat for no reason. Since Matt doesn’t have a celebration hat, he wants to know how many different paths in his land that he can end up with a hat. Two paths are considered to be different if and only if they have different start city or end city. As the counsellor of the mayor Matt, you have to answer this question for him. The celebration elementary students are not stable: sometimes a new crowd of elementary students go to an empty road; sometimes the elementary students on a road will go back home and remain the road empty. Matt will send you the monitor about the change of elementary students on road and ask you the question above. You will be fired if you answer wrong.
Input
The first line of the input contains an integer T, denoting the number of testcases. Then T test cases follow.
For each test case, the first line contains N (1<=N<=30000) describing the number of cities.
Then N lines follow. The ith line of these contains the name of the ith city, it’s a string containing only letters and will not be longer than 10.
The following N - 1 lines indicate the N - 1 edges between cities. Each of these lines will contain two strings for the cities’ name and a integer for the initial status of the edge (0 for empty, 1 for crowded).
Then an integer M (1<=M<=60000) describes the number of queries. There are two kinds of query:
● "M i" means the status changing of the ith (starting from 1) road (0 to 1, 1 to 0);
● "Q" means that Matt asks you the number of different paths.
For each test case, the first line contains N (1<=N<=30000) describing the number of cities.
Then N lines follow. The ith line of these contains the name of the ith city, it’s a string containing only letters and will not be longer than 10.
The following N - 1 lines indicate the N - 1 edges between cities. Each of these lines will contain two strings for the cities’ name and a integer for the initial status of the edge (0 for empty, 1 for crowded).
Then an integer M (1<=M<=60000) describes the number of queries. There are two kinds of query:
● "M i" means the status changing of the ith (starting from 1) road (0 to 1, 1 to 0);
● "Q" means that Matt asks you the number of different paths.
Output
For each test case, first output one line “Case #x:”, where x is the case number (starting from 1).
Then for each “Q” in input, output a line with the answer.
Then for each “Q” in input, output a line with the answer.
Sample Input
1 5 a b c d e a b 1 b c 0 c d 1 d e 1 7 Q M 1 Q M 3 Q M 4 Q
Sample Output
Case #1: 12 8 8 0
题意:n个点的树,每条边有两种权值0,1,想在有两种操作,M i表示将的i条边的值取反,Q操作表示询问书中有多少节点对(u,v)使得u->v路径上1的格式为奇数个。
思路:u->v的路径可以由u->1,1->v两段拼接起来(有可能这两段有重叠的地方,但是重叠的地方计算了两次,所以对结果并没有影响)那么问题就转化成了有多少个节点到1的路径上有奇数个1(假设个数为x),那么剩下的节点(除了根节点1)就是到1有偶数个1的(假设为y),那么答案就是x*y+z(这个是不需要拼接的,距离根节点的距离直接为奇数的),所以先dfs将边排序,并且记录下节点u到根节点的路径上1的奇偶(xor就可以了),然后就是线段树更新,查询了
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=30010;
int N,M,n,tot;
map<string,int> mp;
int head[maxn];
int a[maxn];
struct node
{
int v,next,w;
}edge[maxn*2];
int in[maxn],out[maxn];
void init()
{
tot=n=0;
memset(head,-1,sizeof(head));
}
void add_edge(int u,int v,int w)
{
edge[tot].v=v;
edge[tot].next=head[u];
edge[tot].w=w;
head[u]=tot++;
}
void dfs(int u,int fa,int x)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa)continue;
in[i/2]=++n;
a[n]=x^edge[i].w;
dfs(v,u,x^edge[i].w);
out[i/2]=n;
}
}
struct IntervalTree
{
int sum[maxn<<2];
int setv[maxn<<2];
void build(int o,int l,int r)
{
sum[o]=0;
setv[o]=0;
if(l==r)
{
sum[o]=a[l];
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
void pushup(int o)
{
sum[o]=sum[o<<1]+sum[o<<1|1];
}
void update(int o,int l,int r,int q1,int q2)
{
if(q1<=l&&r<=q2)
{
setv[o]^=1;
sum[o]=r-l+1-sum[o];
return;
}
pushdown(o,l,r);
int mid=(l+r)>>1;
if(q1<=mid)update(o<<1,l,mid,q1,q2);
if(q2>mid)update(o<<1|1,mid+1,r,q1,q2);
pushup(o);
}
void pushdown(int o,int l,int r)
{
if(setv[o])
{
int mid=(l+r)>>1;
setv[o<<1]^=1;
setv[o<<1|1]^=1;
sum[o<<1]=mid-l+1-sum[o<<1];
sum[o<<1|1]=r-mid-sum[o<<1|1];
setv[o]=0;
}
}
}tree;
int main()
{
int T,cas=1;
string name,name1;
int u,v,x;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
mp.clear();
init();
for(int i=1;i<=N;i++)
{
cin>>name;
mp[name]=i;
}
for(int i=1;i<N;i++)
{
cin>>name>>name1;
scanf("%d",&x);
u=mp[name],v=mp[name1];
add_edge(u,v,x);
add_edge(v,u,x);
}
dfs(1,0,0);
tree.build(1,1,n);
scanf("%d",&M);
char op[5];
printf("Case #%d:\n",cas++);
while(M--)
{
scanf("%s",op);
if(op[0]=='Q')
printf("%d\n",tree.sum[1]*(N-tree.sum[1])*2);
else
{
scanf("%d",&x);
x--;
tree.update(1,1,n,in[x],out[x]);
}
}
}
return 0;
}