【bzoj 3578】 GTY的人类基因组计划2(STL的应用)
3578: GTY的人类基因组计划2
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 323 Solved: 145
[Submit][Status][Discuss]
Description
GTY召唤了n个人来做实验,GTY家的房子很大,有m个房间一开始所有人都在1号房间里,GTY会命令某人去某个房间等待做实验,或者命令一段区间的房间开始实验,实验会获得一些实验信息点数,点数为房间里的人数,如果一个房间里的一群人已经做过实验了那么这些人将不会增加实验信息点数(不会增加是针对这一群人的,不是对这群人中的每个人,即1,2,3做了实验,1,2再做实验还会增加2点实验点数)
Input
第一行两个整数n,m,q(n,m,q<=10^5)表示人数,房间数和操作数
接下来q行每行一个操作 "C i j"表示让第i个人去房间j "W l r" 表示让区间[l,r]的房间做实验
Output
对于每一个W操作,输出一个数,表示此次操作所获得的实验点数
Sample Input
3 5 7
C 1 2
C 2 2
W 1 2
C 3 2
W 1 2
C 3 3
W 1 3
C 1 2
C 2 2
W 1 2
C 3 2
W 1 2
C 3 3
W 1 3
Sample Output
3
3
0
3
0
HINT
善用STL
Source
【题解】【STL的应用,一改往常一用STL就荣获TLE的经历啊,看来以前还是使用的不够优越】
【这道题,先给所有的人随机一个值,因为是给一个集合判重,所以判重的时候,将几个人的值异或起来,用map判断是否出现过;将每一次移动后合法的集合即房间号存在set里,每一次移动时,先将相关的两个房间的序号先从set里删掉,再将合法的加入。
记录:每个房间的人数,每个人的编号,每个房间的当前异或值。】
#include<map>
#include<set>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
set<int>s;//存合法的房间号
map<long long,bool>mp;//判重
long long num[100010],p[1000010],b[1000010],h[1000010];
int n,m,q;
int main()
{
int i,j;
srand(1289);
scanf("%d%d%d\n",&n,&m,&q);
for(i=1;i<=n;++i) num[i]=(long long)rand()*rand()%1000000000*(rand()*rand()%2000000000);//给每个人随机一个值
s.insert(1);//因为刚开始所有人都在第一个房间,先将第一个房间加入set
for(i=1;i<=n;++i) h[1]^=num[i],p[1]++,b[i]=1;//h存当前房间的异或值;p存当前房间的人数;b存当前每个人在哪个房间
for(i=1;i<=q;++i)//询问和操作总共不超过10^5,且每次操作只移动一个人,所以范围可以使用STL
{
char c;
int x,y;
scanf("%c",&c);
scanf("%d%d\n",&x,&y);
if(c=='C')
{
if(b[x]==y) continue;//看操作后是否换了房间
s.erase(b[x]); s.erase(y);//将原来的状态移出set
h[b[x]]^=num[x];
p[b[x]]--;
if (!mp[h[b[x]]]) s.insert(b[x]);
h[y]^=num[x];
p[y]++;
if (!mp[h[y]]) s.insert(y);
b[x]=y;
}
else
if(c=='W')
{
int ans=0;
set<int>::iterator it=s.lower_bound(x);
for(;it!=s.end()&&*it<=y;it=s.lower_bound(x))
{
mp[h[*it]]=1;
ans+=p[*it];
s.erase(it);
}
printf("%d\n",ans);
}
}
return 0;
}
既然无能更改,又何必枉自寻烦忧