bzoj 5076: [Lydsy十月月赛]小B的咒语
来源:互联网 发布:金蝶k3软件多少钱 编辑:程序博客网 时间:2024/05/21 14:55
题意
小 B 成为了一个魔法师!他得到了一串由正整数组成的咒语 a。经过他的研究,某一个咒语的威力可以表示为,每个在此咒语中出现过的数字,在这个咒语中最后一次出现与第一次出现的位置之差。小 B 做出了若干次操作,每次操作都有可能是计算咒语的某个子串的威力。同时,小 B 也在不断地实验中,所以操作也有可能是把咒语中某个位置上的数字换成另一个。可是他太小,不会算,请你帮帮他。
题解
这题求出最右端点减去最短端点
不难想到,这个的话对于每一个点,记录上一个是谁
然后把全部加起来
然后一开始是这么想的。。
然后打算用线段树维护。
然后想到一个问题,就是最左端的不可以加
然后想了很久都没想到。。
于是看了下题解CDQ。。
然后才想起来。。
用一个CDQ然后要他的上一个也列入考虑范围了
其实就是把一个点的左边看做(x,pre),权值自然就是(x-pre)
然后你每一次就是看做询问(l,l)到(r,r)这个矩阵里面的和
然后就可以了。。
然后在我不用归并之前,一直T。。改了才过的QAQ
教训
像这种有多个限制的,一定要记得类似CDQ的解法
CODE:
#include<cstdio>#include<algorithm>#include<iostream>#include<cstring>#include<set>using namespace std;typedef long long LL;const int N=100005*10;int n,q;struct qq{ LL x,y;//坐标 int id; int op;//是什么操作 0:加点 1:删点 2:正的询问 3:负的询问}s[N];int tot;LL ans[N];bool ok[N];//这个地方是不是答案set<int> o[N];int next[N],last[N];int k[N];bool cmp (qq x,qq y){return x.x<y.x;}LL f[N];int lb (int x){return x&(-x);}void change (int x,LL y){ while (x<N) { f[x]+=y; x+=lb(x); }}void reset (int x){ while (x<=100000) { f[x]=0; x+=lb(x); }}LL find (int x){ LL lalal=0; while (x>=1) { lalal=lalal+f[x]; x-=lb(x); } return lalal;}qq h[N];void dfs (int l,int r){ if (l==r) return ; int mid=(l+r)>>1; dfs(l,mid);dfs(mid+1,r);/* printf("%d %d\n",l,r); for (int u=l;u<=mid;u++) printf("%lld %lld\n",s[u].x,s[u].y); printf("\n"); for (int u=mid+1;u<=r;u++) printf("%lld %lld\n",s[u].x,s[u].y); system("pause");*/ //sort(s+l,s+1+mid,cmp);sort(s+1+mid,s+1+r,cmp); int now=l; for (int u=mid+1;u<=r;u++) { while (now<=mid) { if (s[now].op==2||s[now].op==3) { now++; continue; } if (s[now].x<=s[u].x) { if (s[now].op==0) change(s[now].y,s[now].x-s[now].y); else change(s[now].y,-(s[now].x-s[now].y)); now++; } else break; } if (s[u].op==2) { ans[s[u].id]+=find(s[u].y); //printf("add:%d %d %d\n",s[u].id,find(s[u].y),s[u].y); } if (s[u].op==3) { ans[s[u].id]-=find(s[u].y); // printf("del:%d %d\n",s[u].id,find(s[u].y)); } } for (int u=l;u<=now;u++) if (s[u].op==0||s[u].op==1) reset(s[u].y); int i=l,j=mid+1; int shen=0; while (i<=mid&&j<=r) { if (s[i].x<s[j].x) h[++shen]=s[i++]; else h[++shen]=s[j++]; } while (i<=mid) h[++shen]=s[i++]; while (j<=r) h[++shen]=s[j++]; for (int u=l;u<=r;u++) s[u]=h[u-l+1]; return ;}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<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f;}set<int>::iterator it;int a[N];int Last[N];//这个值的最后一个是什么int main(){ tot=0; n=read();q=read(); for (int u=1;u<=n;u++) { int x=read(); a[u]=x; last[u]=k[x]; next[k[x]]=u; k[x]=u; Last[x]=u; o[x].insert(u); } for (int u=1;u<=n;u++) if (last[u]!=0) s[++tot]=(qq){u,last[u],0,0}; for (int u=1;u<=q;u++) { char ss[5]; scanf("%s",ss); if (ss[0]=='Q')//询问操作 { ok[u]=true; int l,r; l=read();r=read(); s[++tot]=(qq){r,r,u,2}; s[++tot]=(qq){l-1,r,u,3}; s[++tot]=(qq){r,l-1,u,3}; s[++tot]=(qq){l-1,l-1,u,2}; } else { ok[u]=false; int x,y; x=read();y=read(); //将x这个地方变为y if (Last[a[x]]==x) Last[a[x]]=last[x];//换人了 if (last[x]!=0) s[++tot]=(qq){x,last[x],u,1}; if (next[x]!=0) s[++tot]=(qq){next[x],x,u,1}; if (last[x]!=0&&next[x]!=0)//两边都有,家人 s[++tot]=(qq){next[x],last[x],u,0}; next[last[x]]=next[x]; last[next[x]]=last[x]; o[a[x]].erase(x); //加入新的点 a[x]=y; it=o[y].lower_bound(x);//找到这个值 if (it==o[y].end())//如果没有,那么它就是最后一个了 { if (Last[y]!=0) { s[++tot]=(qq){x,Last[y],u,0}; next[Last[y]]=x; last[x]=Last[y]; } else last[x]=0; Last[y]=x; next[x]=0; } //0:加点 1:删点 else { int now=(*it);//找到位置 if (last[now]!=0)//如果它还有上一个 { s[++tot]=(qq){now,last[now],u,1}; s[++tot]=(qq){x,last[now],u,0}; s[++tot]=(qq){now,x,u,0}; next[last[now]]=x; last[x]=last[now]; last[now]=x; next[x]=now; } else { s[++tot]=(qq){now,x,u,0}; next[x]=now; last[now]=x; last[x]=0; } } o[y].insert(x); } } dfs(1,tot); for (int u=1;u<=q;u++) if (ok[u]) printf("%lld\n",ans[u]); return 0;}
阅读全文
0 0
- bzoj 5076: [Lydsy十月月赛]小B的咒语
- [BZOJ]5074: [Lydsy十月月赛]小B的数字
- bzoj 5074: [Lydsy十月月赛]小B的数字
- bzoj 5071: [Lydsy十月月赛]小A的数字
- bzoj 5071: [Lydsy十月月赛]小A的数字
- 【乱搞】BZOJ5074 [Lydsy十月月赛]小B的数字
- 【bzoj5074】 [Lydsy十月月赛]小B的数字
- bzoj5074 [Lydsy十月月赛]小B的数字
- bzoj 5071: [Lydsy十月月赛]小A的数字 乱搞
- bzoj 5072: [Lydsy十月月赛]小A的树 树形dp
- BZOJ 5072: [Lydsy十月月赛]小A的树 树形dp
- bzoj5071: [Lydsy十月月赛]小A的数字
- bzoj5071 [Lydsy十月月赛]小A的数字
- BZOJ 5071 [Lydsy 十月月赛] 排序 解题报告
- BZOJ 5072 [Lydsy 十月月赛] 树DP 解题报告
- BZOJ5071[Lydsy十月月赛] 小A的数字 解题报告
- BZOJ5072[Lydsy十月月赛] 小A的树 解题报告【树上背包/树形DP】
- bzoj 4972 [Lydsy八月月赛]小Q的方格纸(前缀和)
- 深度学习中的损失函数总结以及Center Loss函数笔记
- rint
- python 入门
- windows Anaconda lightgbm 安装
- java实现递归删除目录及目录下所有文件,递归和非递归方式都有
- bzoj 5076: [Lydsy十月月赛]小B的咒语
- 一、JSP开发环境搭建
- 数据结构实验之查找七:线性之哈希表
- 小学生进位
- 软件工程思维导图
- 12.21
- 深入super,看Python如何解决钻石继承难题
- GAN学习笔记(1):GAN综述
- bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树