NOIP模拟 JZOI5428 查询 【链表】
来源:互联网 发布:灯火阑珊网络电视直播 编辑:程序博客网 时间:2024/06/08 05:37
Description
给出一个长度为n的序列a[]
给出q组询问,每组询问形如(x,y),求a序列的所有区间中,数字x的出现次数与数字y的出现次数相同的区间有多少个
Input
第一行两个数n和q
第二行n个数a[i]
接下来q行,每行两个数x,y表示一组询问
Output
q行,每行一个数表示对应询问的答案
Sample Input
3 2
1 2 1
1 2
4 5
Sample Output
2
6
Data Constraint
对于30%的数据,1<=n<=100,1<=q<=1000
对于另外30%的数据,序列中只有最多50种不同的数字且1<=n<=1000
对于100%的数据,1<=n<=8000,1<=q<=500000,1<=x,y,a[i]<=10^9
解题思路:
对于一个询问设sum1[i]表示a[1]~a[i]中x出现次数,sum2[i]表示a[1]~a[i]中y出现次数,那么我们要求的区间(l,r)即是满足:
移一下项得:
那对于一个r,它的贡献即为满足上述条件的l的个数。(sum1-sum2相当于遇x就+1,遇y就减一,不妨设为sum)
用桶维护一下sum,就可以O(qn)了。
又注意到要是一段序列中既无x,也无y,那sum就不会变,所以我们用链表维护一下每种数字出现的位置,询问中不存在的数字都可看做同一种数字,不妨设为0,那我们只用遍历x,y出现的位置计算贡献即可。同时(x,y)相同的询问只用求一次即可。这样每个位置最多被访问n次(询问搭配数字种数)所以时间复杂度为O(
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<queue>#define ll long longusing namespace std;int getint(){ int i=0,f=1;char c; for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-')f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f;}const int N=8005,M=500005;int n,m,Q;int a[N],b[N],cnt[N<<1],exist[N<<1],ans[M];vector<int>p[N];struct node{ int x,y,id; inline friend bool operator <(const node &a,const node &b) { if(a.x==b.x)return a.y<b.y; return a.x<b.x; }}q[M];void lsh(){ sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1; for(int i=0;i<=m;i++)p[i].push_back(0); for(int i=1;i<=n;i++) { a[i]=lower_bound(b+1,b+m+1,a[i])-b; p[a[i]].push_back(i); } for(int i=0;i<=m;i++)p[i].push_back(n+1); for(int i=1;i<=Q;i++) { if(q[i].x>q[i].y)swap(q[i].x,q[i].y); if(b[lower_bound(b+1,b+m+1,q[i].x)-b]!=q[i].x)q[i].x=0; else q[i].x=lower_bound(b+1,b+m+1,q[i].x)-b; if(b[lower_bound(b+1,b+m+1,q[i].y)-b]!=q[i].y)q[i].y=0; else q[i].y=lower_bound(b+1,b+m+1,q[i].y)-b; } sort(q+1,q+Q+1);}void solve(int x,int y,int vt){ int i=0,j=0,pos=0,tmp=0,sum=n; cnt[n]=0,exist[n]=vt; while(pos!=n+1) { if(p[x][i+1]<=p[y][j+1]) { tmp+=(cnt[sum]+cnt[sum]+p[x][i+1]-pos-1)*(p[x][i+1]-pos)/2; cnt[sum]+=p[x][i+1]-pos; pos=p[x][++i];sum++; if(exist[sum]!=vt)exist[sum]=vt,cnt[sum]=0; } else { tmp+=(cnt[sum]+cnt[sum]+p[y][j+1]-pos-1)*(p[y][j+1]-pos)/2; cnt[sum]+=p[y][j+1]-pos; pos=p[y][++j];sum--; if(exist[sum]!=vt)exist[sum]=vt,cnt[sum]=0; } } while(p[x][i]!=n+1) { tmp+=(cnt[sum]+cnt[sum]+p[x][i+1]-pos-1)*(p[x][i+1]-pos)/2; cnt[sum]+=p[x][i+1]-pos; pos=p[x][++i],sum++; if(exist[sum]!=vt)exist[sum]=vt,cnt[sum]=0; } while(p[y][j]!=n+1) { tmp+=(cnt[sum]+cnt[sum]+p[y][j+1]-pos-1)*(p[y][j+1]-pos)/2; cnt[sum]+=p[y][j+1]-pos; pos=p[y][++j],sum--; if(exist[sum]!=vt)exist[sum]=vt,cnt[sum]=0; } ans[q[vt].id]=tmp;}int main(){ //freopen("lx.in","r",stdin); //freopen("interval.out","w",stdout); n=getint(),Q=getint(); for(int i=1;i<=n;i++) { a[i]=getint(); b[++m]=a[i]; } for(int i=1;i<=Q;i++) q[i].x=getint(),q[i].y=getint(),q[i].id=i; lsh(); for(int k=1;k<=Q;k++) { if(k>1&&q[k].x==q[k-1].x&&q[k].y==q[k-1].y) { ans[q[k].id]=ans[q[k-1].id]; continue; } solve(q[k].x,q[k].y,k); } for(int i=1;i<=Q;i++) cout<<ans[i]<<'\n'; return 0;}
阅读全文
0 0
- NOIP模拟 JZOI5428 查询 【链表】
- NOIP模拟 裁剪表格【链表】
- [NOIP模拟][链表]裁剪表格
- Noip模拟
- 【NOIP模拟】20151004模拟
- 【NOIP模拟】 20151005模拟
- 【NOIP模拟】 20151006模拟
- 【NOIP模拟】 20151007模拟
- 【NOIP模拟】20151014模拟
- 【NOIP模拟】20151015模拟
- NOIP模拟:裁剪表格(链表)
- 【09 NOIP 模拟】light
- [NOIP模拟]Day1
- 8.9CH NOIP模拟
- 8.10FCH NOIP模拟
- 8.13NOIP模拟
- 8.14NOIP模拟
- noip模拟赛 双城记
- [NOIP2017模拟]最佳序列
- 日常运维(八):sync通过服务同步,linux系统日志,screen工具
- Linux基础部分-2.文件相关命令
- Junit4如何正确测试异常
- Google超有趣小实验合集 | 不论你会不会编程,你都可以在这感受到AI的乐趣
- NOIP模拟 JZOI5428 查询 【链表】
- (转)区块链原理最清晰最直观的解释
- 成绩排序
- uORB通信机制和添加自己的topics学习笔记
- Linux基础操作-3.系统命令
- 异常处理练习
- merge-sorted-array Java code
- Logstash日志分析的配置和使用
- Linux基础操作-3.用户和组