题意:给出一个无向图,n个点m条边,有一些操作:Q + 查询所有正边和 Q - 查询所有负边和 Q A 查询所有边和 C X 把跟X邻接的边的权值取反。
思路:这题还是蛮经典的,和hdu 4467 Graph挺像的。就是把顶点度数大于sqrt(m)的点单独拿出来处理,其他的点直接暴力修改。用两个值存所有正边和所有负边的和,修改特殊点的时候,只修改和它相连的也是特殊点之间的边的值,和可以通过维护sum[i][2]算出,这个数组是表示和这个特殊点相连的点的边的正边和负边的和。另外用filp[i]标记这个点,当普通点去修改和它相邻的边时,可以通过两个顶点的filp值来得到当前边的正负……
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=50000+10;
struct Edge
{
int u,v,next;
int w;
Edge (){};
Edge(int uu,int vv,int ww,int nx) {u=uu;v=vv;w=ww;next=nx;}
}edges[maxn<<1];
int head[maxn],nEdge;
int n,m,q,filp[maxn],degree[maxn];
ll a[555][555][2],sum[555][2];
ll res[2];
int hash[maxn],cnt;
void AddEdge(int u,int v,int w)
{
edges[++nEdge]=Edge(u,v,w,head[u]);
head[u]=nEdge;
}
void Init()
{
memset(head,0xff,sizeof(head));
memset(degree,0,sizeof(degree));
memset(hash,0,sizeof(hash));
memset(filp,0,sizeof(filp));
res[0]=res[1]=0;
nEdge=-1;cnt=0;
}
void precal()
{
int lim=(int)sqrt((double)m);
for(int i=1;i<=n;++i)
{
if(degree[i]>lim)
{
hash[i]=++cnt;
}
}
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
int u,v;
for(int i=0;i<nEdge;i+=2)
{
if(edges[i].w>0) res[0]+=edges[i].w;
else res[1]+=edges[i].w;
u=edges[i].u;v=edges[i].v;
if(hash[u]&&hash[v])
{
if(edges[i].w>0)
{
a[hash[u]][hash[v]][0]+=edges[i].w;
a[hash[v]][hash[u]][0]+=edges[i].w;
}
else
{
a[hash[u]][hash[v]][1]+=edges[i].w;
a[hash[v]][hash[u]][1]+=edges[i].w;
}
}
if(hash[u]) sum[hash[u]][edges[i].w<0]+=edges[i].w;
if(hash[v]) sum[hash[v]][edges[i].w<0]+=edges[i].w;
}
}
void changes(int x)
{
if(hash[x])
{
res[0]+=(-sum[hash[x]][1]);
res[0]-=sum[hash[x]][0];
res[1]+=(-sum[hash[x]][0]);
res[1]-=sum[hash[x]][1];
swap(sum[hash[x]][0],sum[hash[x]][1]);
sum[hash[x]][0]*=-1;sum[hash[x]][1]*=-1;
for(int i=1;i<=cnt;++i)
{
if(i==hash[x]) continue;
sum[i][0]-=a[i][hash[x]][0];
sum[i][0]+=(-a[i][hash[x]][1]);
sum[i][1]-=a[i][hash[x]][1];
sum[i][1]+=(-a[i][hash[x]][0]);
swap(a[i][hash[x]][0],a[i][hash[x]][1]);
a[i][hash[x]][0]*=-1;a[i][hash[x]][1]*=-1;
swap(a[hash[x]][i][0],a[hash[x]][i][1]);
a[hash[x]][i][0]*=-1;a[hash[x]][i][1]*=-1;
}
filp[x]^=1;
}
else
{
int v,tmp;
filp[x]^=1;
for(int k=head[x];k!=-1;k=edges[k].next)
{
v=edges[k].v;
if(filp[x]^filp[v]) tmp=-edges[k].w;
else tmp=edges[k].w;
if(tmp>0)
{
res[0]+=tmp;
res[1]-=(-tmp);
if(hash[v])
{
sum[hash[v]][0]+=tmp;
sum[hash[v]][1]-=(-tmp);
}
}
else
{
res[0]-=(-tmp);
res[1]+=tmp;
if(hash[v])
{
sum[hash[v]][0]-=(-tmp);
sum[hash[v]][1]+=tmp;
}
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
char str[5];
//map<ll,int>mp;
int first=true;
while(~scanf("%d%d%d",&n,&m,&q))
{
if(!first) printf("\n");
first=false;
Init();
//mp.clear();
int u,v,w;
for(int i=0;i<m;++i)
{
scanf("%d%d%d",&u,&v,&w);
degree[u]++;degree[v]++;
AddEdge(u,v,w);
AddEdge(v,u,w);
//mp[tmp]=nEdge;
}
precal();
ll ans=0;
int x;
while(q--)
{
scanf("%s",str);
if(str[0]=='Q')
{
scanf("%s",str);
if(str[0]=='A')
ans=res[0]+res[1];
else if(str[0]=='+')
ans=res[0];
else ans=res[1];
printf("%lld\n",ans);
}
else
{
scanf("%d",&x);
changes(x);
}
}
}
return 0;
}