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
Sample Output
3
3
0
题解
可以发现,一次操作最多只能让做实验的房间增加2个,也就是说,总共做实验的次数一定不超过2*q,因此,我们可以用set存可以做实验的房间,每次询问实验点数时二分查找一下,时间复杂度O(qlogq)。
现在的问题在于怎么判重。有一种专门针对集合判重的哈希:对每个人赋一个long long的初值,将一个人加入集合就异或这个特征值,从集合中去掉也异或一遍(异或两遍等于没有异或),这样我们用map搞搞就可以很方便的判重了。
#include <cstdio>
#include <cstdlib>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
LL hash[100001],size[100001],a[100001];
int loc[100001];
set <int> s;
map <LL,bool> pd;
char read[2];
int main()
{
// freopen("test.in","r",stdin);
// freopen("test1.out","w",stdout);
srand(200008017);
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
a[i]=((LL)rand()<<16)|rand();
hash[1]^=a[i];
loc[i]=1;
}
size[1]=n;
s.insert(1);
for(int i=1;i<=q;i++)
{
LL ans=0;
scanf("%s",read);
if(read[0]=='C')
{
int x,y;
scanf("%d%d",&x,&y);
s.erase(loc[x]);
s.erase(y);
hash[loc[x]]^=a[x];
size[loc[x]]--;
hash[y]^=a[x];
size[y]++;
if(!pd[hash[loc[x]]])s.insert(loc[x]);
if(!pd[hash[y]])s.insert(y);
loc[x]=y;
}
else
{
int l,r;
scanf("%d%d",&l,&r);
set<int>::iterator it=lower_bound(s.begin(),s.end(),l);
//printf("fj:%d ",s.count(1));
for(;it!=s.end()&&*it<=r;it=lower_bound(s.begin(),s.end(),l))
{
pd[hash[*it]]=true;
s.erase(it);
ans+=size[*it];
}
printf("%lld\n",ans);
}
}
return 0;
}