bzoj4419: [Shoi2013]发微博 (三种做法)
来源:互联网 发布:长川软件 编辑:程序博客网 时间:2024/05/22 16:00
Description
刚开通的SH微博共有n个用户(1..n标号),在短短一个月的时间内,用户们活动频繁,共有m条按时间顺序的记录:
! x 表示用户x发了一条微博;
+ x y 表示用户x和用户y成为了好友
- x y 表示用户x和用户y解除了好友关系
当一个用户发微博的时候,所有他的好友(直接关系)都会看到他的消息。
假设最开始所有人之间都不是好友关系,记录也都是合法的(即+ x y时x和y一定不是好友,而- x y时x和y一定是好友)。
问这m条记录发生之后,每个用户分别看到了多少条消息。
Input
第1行2个整数n,m。
接下来m行,按时间顺序读入m条记录,每条记录的格式如题目所述,用空格隔开。
Output
输出一行n个用空格隔开的数(行末无空格),第i个数表示用户i最后看到了几条消息。
Sample Input
2 8
! 1
! 2
- 1 2
! 1
! 2
- 1 2
! 1
! 2
Sample Output
1 1
只有第4和第5条记录对应的消息被看到过。其他消息发送时,1和2不是好友。
对100%的数据,N<=200000,M<=500000
感想
这题我有三个方法..
我的是最垃圾的。。
别的都很好
题解
1 线段树(我的)
这个做法很蠢啊。。写了4000B。。
最近思维退化,只会用线段树了
我们可以吧+和,-分开弄
然后离线可以知道每个人按时间顺序依次影响到的是哪些人。。
然后按顺序可以弄成一段连续的区间。。
对于每个人维护一个当前扫到右边的坐标,然后每一次他发信息就整体加上就好了
不想写了
#include<cstdio>#include<algorithm>#include<iostream>#include<cstring>using namespace std;const int N=200005;const int M=500005;int n,m;struct qq{ int c;//0:发微博 1:删除 2:加上 int x,y,id;}s[M],s1[M],s2[M];//原来的操作 增加操作 删除操作 bool cmp (qq a,qq b){ return a.x==b.x?a.id<b.id:a.x<b.x;}int cnt=0,cnt1=0;void ins (){ scanf("%d%d",&n,&m); for (int u=1;u<=m;u++) { char ss[5]; scanf("%s",ss); if (ss[0]=='!') {s[u].c=0;scanf("%d",&s[u].x);continue;} if (ss[0]=='-') { s[u].c=1; scanf("%d%d",&s[u].x,&s[u].y); s1[++cnt]=s[u];s1[cnt].id=cnt; s1[++cnt]=s[u];s1[cnt].id=cnt;swap(s1[cnt].x,s1[cnt].y); } if (ss[0]=='+') { s[u].c=2; scanf("%d%d",&s[u].x,&s[u].y); s2[++cnt1]=s[u];s2[cnt1].id=cnt1; s2[++cnt1]=s[u];s2[cnt1].id=cnt1;swap(s2[cnt1].x,s2[cnt1].y); } } //for (int u=1;u<=m;u++) printf("%d %d %d\n",s[u].x,s[u].y,s[u].c);}int L[N];//这个人增加的左端点在哪里 int R[N];//这个人的右端点到了哪里int L1[N];//这个人的删除左端点到了哪里int R1[N];//这个人的删除左端点到了哪里int now1=0,now2=0;//两个操作给到的编号int a[M],b[M];void prepare (){ if (cnt!=0) { sort(s1+1,s1+1+cnt,cmp); for (int u=1;u<=cnt;u++) { if (s1[u].x!=s1[u-1].x) { L[s1[u].x]=u; R[s1[u].x]=u-1; } a[u]=s1[u].y; //printf("%d ",a[u]); } } if (cnt1!=0) { sort(s2+1,s2+1+cnt1,cmp); for (int u=1;u<=cnt1;u++) { if (s2[u].x!=s2[u-1].x) { L1[s2[u].x]=u; R1[s2[u].x]=u-1; } b[u]=s2[u].y; } }}struct qt{ int l,r; int s1,s2; int c;}tr[M*2];int num=0;void bt (int l,int r){ int a=++num; tr[a].l=l;tr[a].r=r; tr[a].c=0; if (l==r) return ; int mid=(l+r)>>1; tr[a].s1=num+1;bt(l,mid); tr[a].s2=num+1;bt(mid+1,r);}void update (int now){ int s1=tr[now].s1,s2=tr[now].s2; tr[s1].c+=tr[now].c; tr[s2].c+=tr[now].c; tr[now].c=0;}void change (int now,int l,int r){ //printf("%d %d\n",l,r); if (l>r||l==0) return ; if (tr[now].l==l&&tr[now].r==r) { tr[now].c++; return ; } update(now); int s1=tr[now].s1,s2=tr[now].s2; int mid=(tr[now].l+tr[now].r)>>1; if (r<=mid) change(s1,l,r); else if (l>mid) change(s2,l,r); else change(s1,l,mid),change(s2,mid+1,r);}int ans[N];void dfs (int now,int f){ if (tr[now].l==tr[now].r) { ans[a[tr[now].l]]=ans[a[tr[now].l]]+tr[now].c*f; return ; } update(now); dfs(tr[now].s1,f);dfs(tr[now].s2,f);}void dfs1 (int now,int f){ if (tr[now].l==tr[now].r) { ans[b[tr[now].l]]=ans[b[tr[now].l]]+tr[now].c*f; return ; } update(now); dfs1(tr[now].s1,f);dfs1(tr[now].s2,f);}void solve (){//0:发微博 1:删除 2:加上 if (cnt>=1) { num=0;bt(1,cnt); for (int u=1;u<=m;u++) { if (s[u].c==2)//第一次我只弄减法 continue; //printf("%d %d %d %d %d\n",s[u].c,s[u].x,s[u].y,L[s[u].x],R[s[u].x]); if (s[u].c==0) change(1,L[s[u].x],R[s[u].x]); if (s[u].c==1)//减法 { R[s[u].x]++; R[s[u].y]++; } } dfs(1,-1); } /*for (int u=1;u<=n;u++) printf("%d ",ans[u]); printf("\n");*/ if (cnt1>=1) { num=0;bt(1,cnt1); for (int u=1;u<=m;u++) { if (s[u].c==1)//第一次我只弄加 continue; if (s[u].c==0)//加法 change(1,L1[s[u].x],R1[s[u].x]); if (s[u].c==2) { R1[s[u].x]++; R1[s[u].y]++; } } dfs1(1,1); } for (int u=1;u<n;u++) printf("%d ",ans[u]); printf("%d\n",ans[n]);}int main(){ ins(); prepare(); solve(); return 0;}
2 O(n)的做法 CYS的
这个做法应该是最快的吗吧。。
我们就从后往前扫
对于每个人统计一个他当前发了多少个微博
然后当-的时候两个都减去互相当前的微博数
当+的时候两个都加上互相当前的微博数
就可以了
3 网上很普遍的做法 用set或者map都可以
wohenshuai的map写法
然后set都烂大街了,不写了,网上一搜一大把
- bzoj4419: [Shoi2013]发微博 (三种做法)
- [BZOJ4419][Shoi2013]发微博(map)
- [bzoj4419][Shoi2013]发微博(STL)
- 【BZOJ4419】[Shoi2013]发微博【set】
- [BZOJ4419][Shoi2013]发微博
- bzoj4419 [Shoi2013]发微博
- bzoj4419[Shoi2013]发微博
- bzoj 4419: [Shoi2013]发微博 (STL)
- 4419: [Shoi2013]发微博 set
- 【BZOJ】4419: [Shoi2013]发微博
- bzoj 4419: [Shoi2013]发微博
- 4419: [Shoi2013]发微博
- BZOJ 4419 [Shoi2013]发微博
- BZOJ 4419: [Shoi2013]发微博
- 三种红烧肉的做法
- 透明位图的三种做法(转)
- 4419: [Shoi2013]发微博|暴力|set
- BZOJ_P4419 [SHOI2013]发微博(STL+Set)
- 微信APP支付SDK
- 每日英语阅读(五十八)
- Java语言基础学习笔记(六)
- [BZOJ]4418: [Shoi2013]扇形面积并 线段树
- 交换元素
- bzoj4419: [Shoi2013]发微博 (三种做法)
- 动态创建fragment
- android studio 代码风格 ==》color themes
- 关于windows下装Ubuntu
- 准备Java面试之——Java SE基础知识解答(二)
- Servlet程序运行过程及相关错误 404,405,500
- bzoj 4419: [Shoi2013]发微博
- 无限轮播2自动加点
- 安装vue.js的方法