这篇文章会列一点非常规的数据结构题。
tyvj4393 纸条
大意是有若干条纸条,每次操作是把一个纸条挪动一下,然后求一个位置的所有纸条上数的和。所有纸条的长度之和不超过20W,纸条数量啥的都是10W。
首先我们可以分块,不过标解不知道高到哪里去了,对于所有的纸条按照长度大于小于分个类,小于的挪动时暴力修改,大于的反正不到个,询问时枚举一遍就行。
求老司机讲一下线段树的做法…
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> #include <vector> #include <math.h> #include <limits> #include <set> #include <map> using namespace std; #define SZ 233333 #define MP 450 int n,m,q,lp[SZ],M=1,sn=0,ln=0,fff[SZ],lid[SZ],sid[SZ]; struct line {int st,cnt,pos;}sma[SZ],lar[SZ]; int main() { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) { line cur; cur.st=M; scanf("%d%d",&cur.pos,&cur.cnt); for(int j=0;j<cur.cnt;j++) scanf("%d",&lp[M++]); if(cur.cnt>MP) lar[++ln]=cur, lid[i]=ln; else sma[++sn]=cur, sid[i]=sn; } for(int i=1;i<=sn;i++) { for(int j=0;j<sma[i].cnt;j++) fff[sma[i].pos+j]+=lp[sma[i].st+j]; } while(q--) { char ps[6]; int a,b; scanf("%s",ps); if(ps[0]==‘Q‘) { scanf("%d",&a); --a; int ans=fff[a]; for(int j=1;j<=ln;j++) { if(lar[j].pos<=a&&a<=lar[j].pos+lar[j].cnt-1) ans+=lp[lar[j].st+a-lar[j].pos]; } printf("%d\n",ans); } else { scanf("%d%d",&a,&b); if(lid[a]) {lar[lid[a]].pos=b; continue;} int id=sid[a]; for(int j=0;j<sma[id].cnt;j++) { fff[sma[id].pos+j]-=lp[sma[id].st+j]; fff[b+j]+=lp[sma[id].st+j]; } sma[id].pos=b; } } }
tyvj4394 超空间
矩阵加法,询问某一历史版本矩阵的和,回溯到某一历史版本。
矩阵边长在1000以内,询问在2000以内。
可持久化二维树套树?
我们发现这些操作实际上构成了一棵类似操作树的东西。
在这个操作树上我们考虑查询,那么只有操作路径上的东西才会有贡献。
暴力模拟即可。于是就是一道傻逼题。
//代码还没写
嗯如果询问10W?
在树上dfs的时候顺便修改一下二维树状数组似乎就行。
如果边长10W?
在树上dfs的时候顺便修改一下二维线段树似乎就行。
感觉又造出了一道看起来很厉害的数据结构题…
矩阵加法,询问某一历史版本矩阵的和,回溯到某一历史版本。
矩阵边长和询问数量在10W以内。
时间: 2024-10-10 19:15:50