NOIP模拟赛17

5分。。。。

 

T1 LOJ 计算几何瞎暴力

维护以下操作:

1、序列末尾加一个数

2、序列全体从小到大排序

3、查询区间和

4、序列全体异或一个数k

 

序列全体异或一个数,很明显是trie树

那么序列全体从大到小排序就是把一个个数插入trie树的过程

那么就需要一个数组,存储还没有插入trie树的数

 

全体异或:

这里需要两个标记:

xortag表示当前序列是异或了什么,

trie树里1个tag 表示trie树是在异或了tag之后有序

为什么需要标记?

假设当前是二进制第i位,如果i&标记的第i位为真,那么查询的时候1相当于0,0相当于1

为什么要两个标记?

因为有可能对全体执行异或操作,这样原来有序的trie树直接异或就无序了。

所以tag用来表示trie树在当前tag下是有序的序列

查询子树和时,用xortag

在判断向左还是向右走时,要用trie树里的tag

因为trie树里的顺序不变

 

有了标记,查询区间和时,需要维护的就是二进制的每一位1的出现次数

如果&标记的第i为为真,就用0的个数

否则用1的个数

 

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
#define N 200001
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
int xortag,bit[31];
struct TRIE
{
    int len,tag,root;
    int ch[N*31][2],sum[N*31][31],siz[N*31];
    TRIE()
    {
        len=0;
        tag=0;
        root=0;
    }
    void insert(int x)
    {
        int rt=root,id;
        for(int i=29;i>=0;--i)
        {
            id=(x&bit[i])>0;
            if(!ch[rt][id]) ch[rt][id]=++len;
            rt=ch[rt][id];
            siz[rt]++;
            for(int j=0;j<30;++j) 
                if(x&bit[j]) sum[rt][j]++;
        }
    }
    LL getsum(int x)
    {
        LL ans=0;
        for(int i=0;i<30;++i)
            if(xortag&bit[i]) ans+=1ll*(siz[x]-sum[x][i])*bit[i];
            else ans+=1ll*sum[x][i]*bit[i];
        return ans;
    }
    LL query(int x)
    {
        if(!x) return 0;
        int rt=root,l,r;
        LL ans=0;
        for(int i=29;i>=0;--i)
        {
            l=0,r=1;
            if(tag&bit[i]) swap(l,r);
            if(x<=siz[ch[rt][l]]) rt=ch[rt][l];
            else
            {
                ans+=getsum(ch[rt][l]);
                x-=siz[ch[rt][l]];
                rt=ch[rt][r];
            }
        }
        ans+=getsum(rt)/siz[rt]*x;
        return ans;
    }
    int getsiz()
    {
        return siz[ch[root][0]]+siz[ch[root][1]];
    }
}Trie;
struct ARRAY
{
    int len;
    ARRAY()
    {
        len=0;
    }
    int sum[N][31],a[N];
    void insert(int x)
    {
        x^=xortag;
        a[++len]=x;
        for(int i=29;i>=0;i--)
            if(x&bit[i]) sum[len][i]=sum[len-1][i]+1;
            else sum[len][i]=sum[len-1][i];
    }
    void transfer()
    {
        Trie.tag=xortag; 
        for(int i=1;i<=len;i++) Trie.insert(a[i]); 
        len=0;
     }
     LL query(int x)
     {
         LL ans=0;
        for(int i=0;i<30;++i)
             if(xortag&bit[i]) ans+=1ll*(x-sum[x][i])*bit[i];
             else ans+=1ll*sum[x][i]*bit[i];
         return ans;
    }
}Array;
LL query(int x)
{
    int siz=Trie.getsiz();
    if(x<=siz) return Trie.query(x);
    else return Trie.query(siz)+Array.query(x-siz);
}
int main()
{
    freopen("seko.in","r",stdin);
    freopen("seko.out","w",stdout);
    bit[0]=1;
    for(int i=1;i<=30;i++) bit[i]=bit[i-1]<<1;
    int n,m,x;
    read(n);
    for(int i=1;i<=n;++i) read(x),Array.insert(x);
    read(m);
    int ty,u,v;
    while(m--)
    {
        read(ty);
        if(ty==1)
        {
            read(v);
            Array.insert(v);
        }
        else if(ty==2) Array.transfer();
        else if(ty==3)
        {
            read(u);read(v);
            printf("%I64d\n",query(v)-query(u-1));
        }
        else 
        {
            read(v);
            xortag^=v;
        }
    }
    return 0;
}
View Code

 

T2  [ZJOI2008]骑士

基环树DP,断环为链合并

为什么做最大点权独立集不对?

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1000001
using namespace std;
typedef long long LL;
int n,num;
int to[N<<1],nxt[N<<1],front[N],val[N];
int dfn[N],low[N],st[N],top,tot=1,ai[N];
bool cir[N],vis[N];
LL dp[N][2],bi[N][2],ans2,ans;
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}
void init()
{
    read(n);
    int y;
    for(int i=1;i<=n;i++) 
    {
        read(val[i]),read(y);
        add(i,y);
    }
}
void tarjan(int u,int pre)
{
    low[u]=dfn[u]=++tot;
    st[++top]=u;
    vis[u]=true;
    for(int i=front[u];i;i=nxt[i])
    {
        if(i==(pre^1)) continue;
        
            if(!dfn[to[i]]) { tarjan(to[i],i); low[u]=min(low[u],low[to[i]]); }
            else low[u]=min(low[u],dfn[to[i]]),vis[to[i]]=true;
    }
    if(low[u]==dfn[u])
    {
        if(st[top]==u) top--;
        else
        {    
            while(st[top]!=u) 
            {
                cir[st[top]]=true;
                ai[++num]=st[top--];
            }
            top--,ai[++num]=u;
            cir[u]=true;
        }
    }
}
void dfs(int x,int fa)
{
    dp[x][1]=val[x];
    int t;
    for(int i=front[x];i;i=nxt[i])
    {
        t=to[i];
        if(cir[t] || t==fa) continue;
        dfs(t,x);
        dp[x][0]+=max(dp[t][0],dp[t][1]);
        dp[x][1]+=dp[t][0];
    }
}
void unionn()
{
    int tot,t; LL tmp; 
    for(int i=1;i<=n;i++)
    {
        if(vis[i]) continue;
        ans=0;num=0;top=0;
        tarjan(i,0);
        for(int i=1;i<=num;i++) dfs(ai[i],0);
        bi[1][0]=dp[ai[1]][0],bi[1][1]=0;
        for(int i=2;i<=num;i++)
        {
            bi[i][0]=dp[ai[i]][0];
            bi[i][1]=dp[ai[i]][1];
            bi[i][0]+=max(bi[i-1][0],bi[i-1][1]);
            bi[i][1]+=bi[i-1][0];
        }
        ans=max(bi[num][1],bi[num][0]);
        bi[1][0]=0,bi[1][1]=dp[ai[1]][1];
        for(int i=2;i<=num;i++)
        {
            bi[i][0]=dp[ai[i]][0];
            bi[i][1]=dp[ai[i]][1];
            bi[i][0]+=max(bi[i-1][0],bi[i-1][1]);
            bi[i][1]+=bi[i-1][0];
        }
        ans=max(ans,bi[num][0]);
        ans2+=ans;
    }
    printf("%lld",ans2);
}
int main()
{
    //freopen("hoyin.in","r",stdin);
//    freopen("hoyin.out","w",stdout);
    init();
    unionn();
}
View Code

 

T3 [Ynoi2017]由乃的玉米田

http://www.lydsy.com/JudgeOnline/problem.php?id=4810

莫队+bitset

维护两个bitset

第i位表示是否存在值为i的数

一个正着的A,一个反着的B

1、xi-xj=d  ==> xi=d+xj,所以如果 A&A(<<d)有一位为真,就存在 (右移也行)

2、xi+xj=d ==> xi=-xj+d,有负数不好处理,所以 ==> xi=N-xj+d-N=(N-xj)-(N-d) 

     所以若A&(B>>(N-d))有一位为真,就存在

3、xi*xj=d,根号d枚举d的约数,判断是否存在

#include<cstdio>
#include<bitset>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 100001
using namespace std;
bitset <N> A,B;
int n,m,siz;
int a[N],bl[N];
int sum[N];
bool ans[N];
struct node
{
    int ty,l,r,d;
    int id;
}e[N];
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
bool cmp(node p,node q)
{
    if(bl[p.l]!=bl[q.l]) return bl[p.l]<bl[q.l];
    return p.r<q.r;
}
void update(int pos,bool w)
{
    if(w)
    {
        A[a[pos]]=1;
        B[N-a[pos]]=1;
        sum[a[pos]]++;
    }
    else
    {
        sum[a[pos]]--;
        if(!sum[a[pos]]) A[a[pos]]=0,B[N-a[pos]]=0;
    }
}
bool solve(int i)
{
    if(e[i].ty==1) return (A&(A<<e[i].d)).any();
    if(e[i].ty==2) return (A&(B>>(N-e[i].d))).any();
    int d=e[i].d;
    if(!d) return sum[0];
    for(int j=1;j*j<=d;j++) 
        if(!(d%j) && sum[j] && sum[d/j]) return true;
    return false;
}
int main()
{
    freopen("baka.in","r",stdin);
    freopen("baka.out","w",stdout);
    read(n); read(m);
    siz=sqrt(n);
    for(int i=1;i<=n;i++) bl[i]=(i-1)/siz+1;
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=m;i++)
    {
        read(e[i].ty);read(e[i].l);read(e[i].r);read(e[i].d);
        e[i].id=i;
    }
    sort(e+1,e+m+1,cmp);
    int L=1,R=0,l,r;
    for(int i=1;i<=m;i++)
    {
        l=e[i].l; r=e[i].r;
        while(R<r) update(++R,1);
        while(R>r) update(R--,0);
        while(L<l) update(L++,0);
        while(L>l) update(--L,1);
        ans[e[i].id]=solve(i);
    }
    for(int i=1;i<=m;i++) puts(ans[i] ? "seko" : "baka");
}
View Code

 

posted @ 2017-09-28 17:01  TRTTG  阅读(295)  评论(0编辑  收藏  举报