3578: GTY的人类基因组计划2
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 312 Solved: 139
[ 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
C 1 2
C 2 2
W 1 2
C 3 2
W 1 2
C 3 3
W 1 3
Sample Output
3
0
HINT
善用STL
Source
题解:STL+hash
因为一个组的人只能做一次实验,例如{1,2,3}在实验室1做过试验了,那么这一组人在1或者其他组做实验就都不计算了。所以我们需要用hash判断这组人是否做过实验了。
于是我们给每个人一个long long 范围的值,然后每个组的值就是组中成员的值的异或和,然后用map映射来进行判重。
这道题的范围是10^5,暴力肯定不行,如果只是求区间和的话可以用线段树,但是我们还需要给区间出现过的值打标记(map),这就不太好了。
因为操作一共10^5,只有更改后才有可能出现新的组合,那么可做实验的房间数最多不超过Q个,那么每次可做实验的房间数是有限的,均摊的时间复杂度不会很高,所以我们考虑到set集合,每次把可以计算实验点数的房间扔进集合里,因为集合中的数字有序,所以我们可以通过stl中的lower_bound 查询集合中大于等于x的数,然后依次弹出集合,就可以了。
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<set>
#define N 500000
#define LL long long
using namespace std;
int n,m,k,tree[N];
map<LL,LL> mp;
set<int> s;
LL num[N],hp[N];
int size[N],mark[N],pos[N];
int main()
{
scanf("%d%d%d",&n,&m,&k);
srand(2016+7+6);
for (int i=1;i<=n;i++)
{
LL x,y,z;
x=rand()*rand()%1000000000;
y=rand()*rand()%2000000000;
num[i]=(LL)x*y;
hp[1]^=num[i];
pos[i]=1;
}
mp.clear();
size[1]=n;
s.insert(1);
for (int i=1;i<=k;i++)
{
char s1[10];
scanf("%s",s1);
if (s1[0]=='C')
{
int x,y; scanf("%d%d",&x,&y);
if (pos[x]==y) continue;
s.erase(pos[x]);
s.erase(y);
hp[pos[x]]^=num[x]; size[pos[x]]--;
if (mp[hp[pos[x]]]!=1) s.insert(pos[x]);
pos[x]=y; size[pos[x]]++;
hp[pos[x]]^=num[x];
if (mp[hp[pos[x]]]!=1) s.insert(pos[x]);//括号里如果是int,那么表示把当前数扔进集合
}
else
{
int x,y; scanf("%d%d",&x,&y);
int ans=0;
set<int>::iterator it=s.lower_bound(x);//it存储的是X的位置
for (;it!=s.end()&&*it<=y;it=s.lower_bound(x))
{
mp[hp[*it]]=1;
ans+=size[*it];
s.erase(it);//括号里如果是指针,那么表示把当前位置的数删除
}
printf("%d\n",ans);
}
}
}