题目大意:
给出三个数N, M, Q (1 <= N <= 5*10^4, 1 <= M <= 15*10^4, 1 <= Q <= 25*10^4)
表示现在有N个人在一组聊天系统中, 接下来给出一个O(1 <= O <= n), 然后是O个数代表着O个人初始时在线
然后是M组两个数, 代表两者初始的时候互为好友, 然后是Q次操作, 每次操作可能是某人上线或下线, 可以是两人建立好友关系或者取消好友关系, 还有可能是询问某人的好友列表当中现在在线的人的数量
大致思路:
刚开始直接模拟, 第8组test就超时了, 后来改用分块来做, 将度数高于sqrt(N)的点视为重点, 否则视为轻点, 用O[x]表示与点x相连的轻点中在线的个数, H[x]表示与x相连的重点的点的集合, 每次更新的时候根据当前点是轻点还是重点来更新, 但是还是跪在了第35组数据...(TLE)
后来学了下葱酱的写法, 因为在操作过程中点的度数一只在变化, 使用固定的sqrt(N)来作为判断标准并不太合适, 对于每个点, 用heavy[x]表示与点x相连的比点x重的点的个数, 并且将这些点用vector保存下来, 用L[x]表示与x相连的点中比x轻的染色(在线)的点的个数, 对于两个相连的点, 相对地用轻重来判断, 而不是用单纯的度数是否大于sqrt(N)来判断轻重
代码如下:
Result : Accepted Memory : 4200 KB Time : 249 ms
/*
* Author: Gatevin
* Created Time: 2015/3/3 14:10:55
* File Name: Shana.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
const int maxn = 50010;
int N, M, Q, O;
int x, y;
char op[4];
bool on[maxn];//表示某个点是否被染色(是否上线)
int heavy[maxn];//表示比该点重的相连的点数
vector <int> G[maxn];//G[x]中保存的是比x重的相连的点
int L[maxn];//L[x]表示比x轻的与x相连的点中被染色的点的数量
void add()
{
scanf("%d %d", &x, &y);
if(heavy[x] > heavy[y]) swap(x, y);
heavy[x]++;//比x重的点数量+1
G[x].push_back(y);
L[y] += on[x];//比y轻的点如果在线L[y] += 1
return;
}
void del()
{
scanf("%d %d", &x, &y);
int v = -1;
for(unsigned int i = 0; i < G[x].size(); i++)
if(G[x][i] == y) v = i;//找到存储的位置
if(v == -1)//说明y比x轻
{
swap(x, y);
for(unsigned int i = 0; i < G[x].size(); i++)
if(G[x][i] == y) v = i;
}
if(on[x]) L[y]--;//删掉边(x, y)则比y轻的点被染色的点数量减少
heavy[x]--;//比x重的点y删去
G[x][v] = G[x][G[x].size() - 1];
G[x].pop_back();
return;
}
void online()
{
scanf("%d", &x);
on[x] = 1;
for(unsigned int i = 0; i < G[x].size(); i++) L[G[x][i]]++;//所有比x重且相连的点对应的L[]加1
return;
}
void offline()
{
scanf("%d", &x);
on[x] = 0;
for(unsigned int i = 0; i < G[x].size(); i++) L[G[x][i]]--;//所有比x重且相连的店对应的L[]减1
return;
}
void query()
{
scanf("%d", &x);
int ans = L[x];//比x轻的点
for(unsigned int i = 0; i < G[x].size(); i++)
if(on[G[x][i]]) ans++;//比x重的点
printf("%d\n", ans);
return;
}
int main()
{
scanf("%d %d %d %d", &N, &M, &Q, &O);
while(O--)
scanf("%d", &x), on[x] = 1;
while(M--)
add();
while(Q--)
{
scanf("%s", op);
switch(op[0])
{
case 'A': add(); break;
case 'D': del(); break;
case 'O': online(); break;
case 'F': offline(); break;
case 'C': query(); break;
}
}
return 0;
}