BZOJ 4103~4105 THUSC2015 题解

T1:BZOJ 4013 xor
题目大意:给定一个长度为 n 的数列 a 和一个长度为 m 的数列 b ,给定矩阵 A ,令 Ai,j=aibj q 次询问某个子矩形里的 k 大值
n1000,m3105,q500

刚看到这题的时候我发现我不会,看到数据范围的时候我发现出题人也不会……
如果 n=1 ,那么我们对这 m 个数建立可持久化Trie树,每次询问的时候查询异或 a1 k 大值即可
那么现在 n=1000 ,我们只需要把这 2000 棵Trie树放在一起跑即可
时间复杂度 O(m32+nq32)
二分答案会T掉。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
struct Trie{
    Trie *son[2];
    int val;
    void* operator new (size_t,Trie *_,Trie *__,int ___)
    {
        static Trie *mempool,*C=mempool;
        if(C==mempool)
            mempool=(C=new Trie[1<<15])+(1<<15);
        C->son[0]=_;
        C->son[1]=__;
        C->val=___;
        return C++;
    }
    friend Trie* Insert(Trie *p,int x,int digit)
    {
        if(!digit)
            return new (p->son[0],p->son[1],p->val+1)Trie;
        if(x&digit)
            return new (p->son[0],Insert(p->son[1],x,digit>>1),p->val+1)Trie;
        else
            return new (Insert(p->son[0],x,digit>>1),p->son[1],p->val+1)Trie;
    }
    friend int Get_Kth(Trie *stack1[],Trie *stack2[],int stack3[],int top,int digit,int k)
    {
        int i,temp=0;
        if(!digit)
            return 0;
        for(i=1;i<=top;i++)
        {
            temp+=stack1[i]->son[stack3[i]&digit?0:1]->val;
            temp-=stack2[i]->son[stack3[i]&digit?0:1]->val;
        }
        if(k<=temp)
        {
            for(i=1;i<=top;i++)
            {
                stack1[i]=stack1[i]->son[stack3[i]&digit?0:1];
                stack2[i]=stack2[i]->son[stack3[i]&digit?0:1];
            }
            return digit|Get_Kth(stack1,stack2,stack3,top,digit>>1,k);
        }
        else
        {
            for(i=1;i<=top;i++)
            {
                stack1[i]=stack1[i]->son[stack3[i]&digit?1:0];
                stack2[i]=stack2[i]->son[stack3[i]&digit?1:0];
            }
            return Get_Kth(stack1,stack2,stack3,top,digit>>1,k-temp);
        }
    }
}*tree[M];
int n,m,q;
int a[1010],b[M];
Trie *stack1[1010],*stack2[1010];
int stack3[1010],top;
int main()
{
    int i,k,l1,r1,l2,r2;
    cin>>n>>m;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<=m;i++)
        scanf("%d",&b[i]);
    tree[0]=new (0x0,0x0,0)Trie;
    tree[0]->son[0]=tree[0]->son[1]=tree[0];
    for(i=1;i<=m;i++)
        tree[i]=Insert(tree[i-1],b[i],1<<30);
    for(cin>>q;q;q--)
    {
        scanf("%d%d%d%d%d",&l1,&r1,&l2,&r2,&k);
        top=0;
        for(i=l1;i<=r1;i++)
        {
            stack1[++top]=tree[r2];
            stack2[  top]=tree[l2-1];
            stack3[  top]=a[i];
        }
        printf("%d\n",Get_Kth(stack1,stack2,stack3,top,1<<30,k));
    }
    return 0;
}

T2:BZOJ 4015 square
题目大意:维护一个序列,支持两种操作:
1.将区间的每个数 x 改为 x2 mod p
2.求区间和(不取模)

观察题目中给的模数,我们可以打个表,发现任何一个数到环的距离不超过 11 ,而且所有环长的 Lcm 不超过 60
然后就是花神的游览计划了……
对于不在环上的节点我们暴力修改 对于所有节点都在环上的区间直接用一个链表维护这个环 然后区间求平方的时候向前走一位就行了
时间复杂度 O(nlogn60)
似乎这个题过的人很少?

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m,p;
int v[M],on_ring[M],T;
struct List{
    int val;
    List *next;
    friend List* Merge(List *r2,List *r3,int len)
    {
        int i;
        List *head=new List,*r1=head;
        r1->val=r2->val+r3->val;
        for(i=2;i<=len;i++)
        {
            r1->next=new List;
            r1=r1->next;
            r2=r2->next;
            r3=r3->next;
            r1->val=r2->val+r3->val;
        }
        return r1->next=head;
    }
    friend void Merge(List *r1,List *r2,List *r3,int len)
    {
        int i;
        for(i=1;i<=len;i++)
        {
            r1->val=r2->val+r3->val;
            r1=r1->next;
            r2=r2->next;
            r3=r3->next;
        }
    }
};
List* Get_Ring(int x,int &len)
{
    List *head=new List,*last=head;
    int i;
    head->val=x;len=1;
    for(i=x*x%p;i!=x;i=i*i%p)
    {
        last->next=new List;
        last=last->next;
        last->val=i;len++;
    }
    return last->next=head;
}
struct Segtree{
    Segtree *ls,*rs;
    int sum,len,mark;
    List *ring;
    void* operator new (size_t)
    {
        static Segtree mempool[M<<1],*C=mempool;
        return C++;
    }
    void Rotate(int x)
    {
        mark+=x;
        for(x%=len;x;x--)
            ring=ring->next;
        sum=ring->val;
    }
    void Push_Up()
    {
        if(!len&&ls->len&&rs->len)
        {
            len=ls->len*rs->len/__gcd(ls->len,rs->len);
            ring=Merge(ls->ring,rs->ring,len);
        }
        sum=ls->sum+rs->sum;
        Merge(ring,ls->ring,rs->ring,len);
    }
    void Push_Down()
    {
        if(mark)
        {
            ls->Rotate(mark);
            rs->Rotate(mark);
            mark=0;
        }
    }
    void Build_Tree(int x,int y,int a[])
    {
        int mid=x+y>>1;
        if(x==y)
        {
            sum=a[mid];
            if(on_ring[sum])
                ring=Get_Ring(sum,len);
            return ;
        }
        (ls=new Segtree)->Build_Tree(x,mid,a);
        (rs=new Segtree)->Build_Tree(mid+1,y,a);
        Push_Up();
    }
    void Modify(int x,int y,int l,int r)
    {
        int mid=x+y>>1;
        if(x==l&&y==r)
        {
            if(len)
                Rotate(1);
            else if(x==y)
            {
                sum=sum*sum%p;
                if(on_ring[sum])
                    ring=Get_Ring(sum,len);
            }
            else
            {
                ls->Modify(x,mid,l,mid);
                rs->Modify(mid+1,y,mid+1,r);
                Push_Up();
            }
            return ;
        }
        Push_Down();
        if(r<=mid)
            ls->Modify(x,mid,l,r);
        else if(l>mid)
            rs->Modify(mid+1,y,l,r);
        else
            ls->Modify(x,mid,l,mid) , rs->Modify(mid+1,y,mid+1,r) ;
        Push_Up();
    }
    int Get_Ans(int x,int y,int l,int r)
    {
        int mid=x+y>>1;
        if(x==l&&y==r)
            return sum;
        Push_Down();
        if(r<=mid)
            return ls->Get_Ans(x,mid,l,r);
        if(l>mid)
            return rs->Get_Ans(mid+1,y,l,r);
        return ls->Get_Ans(x,mid,l,mid) + rs->Get_Ans(mid+1,y,mid+1,r) ;
    }
}*tree=new Segtree;
void DFS(int x)
{
    if(v[x])
    {
        if(v[x]!=T)
            return ;
        int i=x;
        do{
            on_ring[i]=true;
            i=i*i%p;
        }while(i!=x);
        return ;
    }
    v[x]=T;
    DFS(x*x%p);
}
int main()
{
    #ifdef PoPoQQQ
    freopen("4105.in","r",stdin);
    freopen("4105.out","w",stdout);
    #endif
    static int a[M];
    int i,op,x,y;
    cin>>n>>m>>p;
    for(i=0;i<p;i++)
        if(!v[i])
            ++T,DFS(i);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    tree->Build_Tree(1,n,a);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&x,&y);
        if(op==0)
            tree->Modify(1,n,x,y);
        else
            printf("%d\n",tree->Get_Ans(1,n,x,y));
    }
    return 0;
}

T3:BZOJ 4014 decipher
题目大意:给定一个字符串,将这个字符串后面加一个’.’,然后将所有与这个字符串环同构的串排个序,把最后一列给你,要求输出原串
傻逼题放在T3已经成为了一种传统了么=- -=
看代码对着样例多理解理解吧这题实在说不明白

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
int n,m;
int a[M],b[M],c[M],d[M],ans[M];
bool Compare(int x,int y)
{
    if(a[x]!=a[y])
        return a[x]<a[y];
    if(b[x]!=b[y])
        return b[x]<b[y];
    return x<y;
}
int main()
{
    int i;
    cin>>n>>m;
    for(i=1;i<=n+1;i++)
        scanf("%d",&a[i]);
    for(i=1;i<=n+1;i++)
        b[i]=a[i];
    sort(b+1,b+n+2);
    for(i=1;i<=n+1;i++)
        c[i]=i;
    sort(c+1,c+n+2,Compare);
    for(i=1;i<=n+1;i++)
        d[c[i]]=i;
    int pos=1;
    for(i=n;i;i--)
    {
        ans[i]=a[pos];
        pos=d[pos];
    }
    for(i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}

你可能感兴趣的:(线段树,Trie树,bzoj,可持久化数据结构)