不明觉厉的数据结构题

这篇文章会列一点非常规的数据结构题。

tyvj4393 纸条

大意是有若干条纸条,每次操作是把一个纸条挪动一下,然后求一个位置的所有纸条上数的和。所有纸条的长度之和不超过20W,纸条数量啥的都是10W。

首先我们可以分块,不过标解不知道高到哪里去了,对于所有的纸条按照长度大于小于$\sqrt{n}$分个类,小于$\sqrt{n}$的挪动时暴力修改,大于$\sqrt{n}$的反正不到$\sqrt{n}$个,询问时枚举一遍就行。

求老司机讲一下线段树的做法…

#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以内。

可持久化二维树套树?

我们发现这些操作实际上构成了一棵类似操作树的东西。

在这个操作树上我们考虑查询,那么只有操作路径上的东西才会有贡献。

暴力模拟即可。于是就是一道傻逼题。

#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;
typedef long long ll;
#define SZ 233333
int ct=0,n,q,x1[SZ],x2[SZ],y1[SZ],y2[SZ],vv[SZ],fa[SZ];
int main()
{
    scanf("%d%d",&n,&q);
    int cur=0;
    for(int i=1;i<=q;i++)
    {
        char s[7]; scanf("%s",s);
        if(s[1]=='a'||s[1]=='o') //Raise/Lower
        {
            int a,b,c,d,e;
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
            e*=(s[1]=='o')?-1:1;
            ++ct; x1[ct]=a; y1[ct]=b;
            x2[ct]=c; y2[ct]=d; vv[ct]=e;
            fa[ct]=cur; cur=ct;
        }
        else if(s[1]=='u') //Query
        {
            int t,_x1,_y1,_x2,_y2;
            scanf("%d%d%d%d%d",&t,&_x1,&_y1,&_x2,&_y2);
            ll ans=0;
            while(t)
            {
                int x_1=max(_x1,x1[t]);
                int y_1=max(_y1,y1[t]);
                int x_2=min(_x2,x2[t]);
                int y_2=min(_y2,y2[t]);
                ans+=(ll)vv[t]*max(x_2-x_1+1,0)*max(y_2-y_1+1,0);
                t=fa[t];
            }
            printf("%lld\n",ans);
        }
        else
        {
            int x; scanf("%d",&x); cur=x;
        }
    }
}

嗯如果询问10W?

离线地做。

在树上dfs的时候顺便修改一下二维树状数组似乎就行。

如果边长10W?

在树上dfs的时候顺便修改一下二维线段树似乎就行。

感觉又造出了一道看起来很厉害的数据结构题…

矩阵加法,询问某一历史版本矩阵的和,回溯到某一历史版本。

矩阵边长和询问数量在10W以内。

代码不想写了…谁爱写谁写

9CD1M[RTWF@(KI1U7KNC4(E

本来还想放几道题的…但是题解写不出来等有空再补

posted @ 2016-04-25 17:04  fjzzq2002  阅读(377)  评论(0编辑  收藏  举报