bzoj 4419: [Shoi2013]发微博 乱搞

来源:互联网 发布:ven .js 编辑:程序博客网 时间:2024/06/09 14:26

题意

刚开通的SH微博共有n个用户(1..n标号),在短短一个月的时间内,用户们活动频繁,共有m条按时间顺序的记录:
! x 表示用户x发了一条微博;
+ x y 表示用户x和用户y成为了好友
- x y 表示用户x和用户y解除了好友关系
当一个用户发微博的时候,所有他的好友(直接关系)都会看到他的消息。
假设最开始所有人之间都不是好友关系,记录也都是合法的(即+ x y时x和y一定不是好友,而- x y时x和y一定是好友)。
问这m条记录发生之后,每个用户分别看到了多少条消息。
对100%的数据,N<=200000,M<=500000

分析

唉做了一晚上的不可做题,刷道水题放松一下先。

考虑每一个点x对其他点的贡献。从前往后遍历所有与x有关的操作,维护一个变量now表示当前x一共发了多少条微博。若碰到加入一个点,则把该点的ans减去now。当删掉一个点时,则把该点的ans加上now即可。
注意那些不会被删掉的点。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=200005;int n,m,tot,last[N],now;struct data{int to,op,next;}a[N*5];bool vis[N];LL ans[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void solve(int x){    if (!x) return;    solve(a[x].next);    if (a[x].op==1) now++;    else if (a[x].op==2) ans[a[x].to]-=now,vis[a[x].to]=1;    else ans[a[x].to]+=now,vis[a[x].to]=0;}void work(int x){    if (!x) return;    work(a[x].next);    if (a[x].op>1&&vis[a[x].to]) vis[a[x].to]=0,ans[a[x].to]+=now;}int main(){    n=read();m=read();    for (int i=1;i<=m;i++)    {        char ch[2];        scanf("%s",ch);        if (ch[0]=='!')        {            int x=read();            a[++tot].op=1;a[tot].next=last[x];last[x]=tot;        }        else        {            int x=read(),y=read();            if (ch[0]=='+') a[tot+1].op=a[tot+2].op=2;            else a[tot+1].op=a[tot+2].op=3;            a[++tot].to=y;a[tot].next=last[x];last[x]=tot;            a[++tot].to=x;a[tot].next=last[y];last[y]=tot;        }    }    for (int i=1;i<=n;i++) now=0,solve(last[i]),work(last[i]);    for (int i=1;i<n;i++) printf("%lld ",ans[i]);    printf("%lld",ans[n]);    return 0;}
原创粉丝点击