51Nod 算法马拉松24

A : 构造
B : 状压DP
C : 构造
D : 线段树或平衡树
E : 树链剖分+线段树
F : Unfinished


A 1804 小C的多边形

强行猜了一个结论,试了一下小数据发现没问题,那就假装没问题吧……就是外面一圈1~n-1,里面把1插在n-2和n-1之间,其他的顺次递推。

本题考察输出优化的使用。

#include
using namespace std;
namespace runzhe2000
{
    int n, last = 1, sum, tot; char buff[20000000];
    void print_char(char c){buff[++tot] = c;}
    void print_int(int x)
    {
        if(x>9)print_int(x/10);
        buff[++tot] = (x%10+'0');
    }
    void print_close(){puts(buff+1);}
    void main()
    {
        scanf("%d",&n); n--; if(~n&1){puts("0");return;} sum = 3*(n+1)>>1;
        for(int i = 1; i <= n; i++) print_int(i),print_char(' '); print_char('\n');
        for(int i = 1; i <= n; i++) print_int(last = sum - ((i-1+n)%n?(i-1+n)%n:n) - last),print_char(' ');
        print_close();
    }
}
int main()
{
    runzhe2000::main();
}

B 1779 逆序对统计

按数字从小到大做,记 f[i][s] 表示做到第i小的数字,此时已经填完的状态为s,枚举这个i填不填即可。

这样是 O(2nm) 的,理论上应该是可以过的,然而本机测了两种大同小异的大数据,一种全是1~20的正序循环的数据1s-跑出,另一种全是20~1的逆序循环7s+跑出。看了一下操作次数发现并没有什么问题,就很纳闷了。后来研究了一下,发现把可用状态丢进队列的话,内存访问很不连续,还不如直接顺序枚举所有状态……论不懂常数的危害QAQ

#include
#include
#include
#define N 22
#define M 105
#define cmax(u,v) ((u)<(v)?(u)=(v):0)
using namespace std;
namespace runzhe2000
{
    const int INF = 1<<29;
    int n, m, f[2][1<1<void main()
    {
        happy = scanf("%d%d",&n,&m);
        for(int i = 0; i < (1<memset(f, -63, sizeof(f)); f[cur][0] = 0;
        for(int i = 1, pos; i <= m; i++, cur ^= 1)
        {
            happy = scanf("%d",&pos);
            int *fc = f[cur], *fcc = f[cur^1], p = 1<<(pos-1);
            for(int s = (1<1; ~s; s--)
            {
                int v = fc[s];
                cmax(fcc[s], v); 
                if(~s&p)
                {
                    int ss = s | p, tmp = v + popcount[s>>pos];
                    cmax(fcc[ss], tmp);
                }
                fc[s] = -INF;
            }
        }
        printf("%d\n",f[cur][(1<1]);
    }
}
int main()
{
    runzhe2000::main();
}

C 1851 俄罗斯方块

看上去好像非常复杂,实际上用这些方块已经能弄出很多图形了……首先一个显然的结论是奇数个1不可能完成,以下讨论均默认偶数个1。

考虑我们用一个T形的和一个Z形的即可构出如下的反转方案
100
100

同样,用一个L形的和一个Z形的即可构出如下的反转方案
010
100

也就是说,如果不考虑边界,我们可以把一个1直接挪到它的八个邻点之一。理论上如果边界无限远则任意一种局面都可行。考虑边界是怎样的,不妨设n<=m,易证如果n>=2并且m>=3就一定可以。考虑更小的边界,对于2×2的暴力判一下即可。剩下的,对于n=1的情况手动用I形的覆盖一下即可……

#include
#include
#define N 10000005
using namespace std;
namespace runzhe2000
{
    int read01(){char c = getchar(); for(; c != '0' && c != '1'; c = getchar()); return c - '0';}
    int a[N], n, m, T;
    void main()
    {
        scanf("%d",&T);
        for(; T--; )
        {
            int cnt = 0, siz = 0; scanf("%d%d",&n,&m);
            for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) cnt += (a[++siz] = read01());
            if(cnt&1) puts("No");
            else
            {
                if((n>=2 && m>=3) || (m>=2 && n>=3)) puts("Yes");
                else if(n == 2 && m == 2) puts((cnt&&cnt!=4)?"No":"Yes");
                else
                {
                    n > m ? m = n: 0;
                    if(m <= 3) puts(cnt?"No":"Yes");
                    else
                    {
                        for(int i = 1, ii = m-3; i <= ii; i++) 
                            if(a[i])
                            {
                                cnt -= a[i] + a[i+1] + a[i+2] + a[i+3];
                                a[i] ^= 1; a[i+1] ^= 1; a[i+2] ^= 1; a[i+3] ^= 1;
                                cnt += a[i] + a[i+1] + a[i+2] + a[i+3];
                            }
                        puts(cnt?"No":"Yes");
                    }
                }
            }
        }
    }
}
int main()
{
    runzhe2000::main();
}

D 1680 区间求和

考虑已经知道区间[l,r]的答案,现在在r后面加入a[i] (r+1=i),区间[l,i]的答案会变成什么。记区间[l,r]的答案为sum,c表示[l,r]里面比a[i]小的数的个数,s表示[l,r]里面比a[i]大的数的和,则推一下发现[l,i]的答案是 sum+(c+1)*a[i]+s。

推广下去,考虑已经知道了区间[l,r]以及其所有子区间的答案,同样加入一个a[i],考虑区间[l,i]以及其所有子区间的答案会变成什么。同样推一下得到答案是: sum+a[j]>a[i]ja[j]+(a[k]<a[i]k+i)a[i]

实际上并不一定要严格小于或大于,a相等的随便归到其中一类就行了。分别维护式子后两项两个求和即可。

这个东西线段树和平衡树都可以做,然而我好久没碰平衡树了,因此写了一发splay,怒卡了3波常数才过???(大概不作死就不会死)

还垫底了- -

#include
#define N 1000005
#define MOD 1000000007
using namespace std;
namespace runzhe2000
{
    typedef long long ll;
    const int INF = 1<<30;
    int happy, n, a[N], A, B, C;
    struct node
    {
        node *ch[2], *fa;
        int v, v1, v2, sum1, sum2;
    }mem[N], *tot, *null, *root;
    node* newnode(){node *p = ++tot; *p = *null; return p;}
    void init()
    {
        null = tot = mem; null->ch[0] = null->ch[1] = null->fa = null;
        null->v1 = null->v2 = null->sum1 = null->sum2 = 0;
        node *p = newnode(); p->v = -INF; root = newnode(); root->v = INF;
        p->fa = root, root->ch[0] = p;
    }
    int type(node *x){return x->fa->ch[1]==x;}
    void pushup(node *x)
    {
        x->sum1 = ((x->v1 + x->ch[0]->sum1)%MOD + x->ch[1]->sum1)%MOD;
        x->sum2 = ((x->v2 + x->ch[0]->sum2)%MOD + x->ch[1]->sum2)%MOD;
    }
    void rotate(node *x)
    {
        node *f = x->fa; int d = type(x);
        (x->fa = f->fa) != null ? x->fa->ch[type(f)] = x : 0;
        (f->ch[d] = x->ch[!d]) != null ? f->ch[d]->fa = f : 0;
        x->ch[!d] = f, f->fa = x; pushup(f);
    }
    void splay(node *x)
    {
        for(; x->fa != null; )
        {
            if(x->fa->fa == null) rotate(x);
            else if(type(x->fa) == type(x)) rotate(x->fa), rotate(x);
            else rotate(x), rotate(x);
        }
        pushup(root = x);
    }
    void insert(node *x, node *f, node *p, int t)
    {
        if(x == null){p->fa = f; f->ch[t] = p; return;}
        if(x->v <= p->v) insert(x->ch[1], x, p, 1);
        else insert(x->ch[0], x, p, 0); pushup(x);
    }
    void main()
    {
        happy = scanf("%d%d%d%d%d",&n,&a[1],&A,&B,&C); 
        init(); ll ans = 0, sum = 0;
        for(int i = 2; i <= n; i++) a[i] = ((ll)a[i-1] * A + B) % C;
        for(int i = 1; i <= n; i++)
        {
            node *x = newnode(); x->v = a[i], x->v1 = (ll)i*a[i]%MOD, x->v2 = i;
            insert(root, null, x, 0); splay(x); 
            sum = (sum + root->ch[1]->sum1 + (ll)(root->ch[0]->sum2 + i) * a[i] % MOD ) % MOD;
            (ans += sum) %= MOD;
        }
        printf("%lld\n",ans);
    }
}
int main()
{
    runzhe2000::main();
}

E 1819 黑白树 V2

我们考虑所有黑点与点x的LCA之和等于什么,就等于:x子树内的黑点个数 * x + x的所有祖先f的子树内的所有不在x到f的路径上的黑点个数*f

前者就直接用一个线段树搞一搞。

对于后者,其实就是根到x的一个链上信息,考虑LCT。列了一下大概要差不多十种标记才能维护清楚这个东西(还不知道有没有想错,代码能力太弱果断弃)……既然LCT似乎能做,考虑树剖?把这条链拆成若干重链,对每一条重链维护信息,重链交接的地方单独做一下即可。同样上一颗线段树维护即可, O(mlog2n)

做法口胡完了QAQ。实际上对于后者,要维护的信息还是很多,比如轻边的子树内黑点个数,区间奇数层取反完值会变化多少等等……

不得不说51Nod的评测机是真的快,本机极限数据跑了差不多10s,我还他以为卡两个log。正在绝望之际,交一发,1.5s就过出来了……其实大概是本机太慢了吧,这个电脑连打字都越来越卡了……

#include
#define N 200005
using namespace std;
namespace runzhe2000
{
    typedef long long ll;
    int read()
    {
        int r = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar());
        for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
        return r;
    }

    int n, m, last[N], ecnt, c[N], top[N], siz[N], fa[N], son[N], dep[N], beg[N], rebeg[N], end[N], timer;
    struct edge{int next, to;}e[N<<1];
    void addedge(int a, int b){e[++ecnt] = (edge){last[a], b}; last[a] = ecnt;}
    void dfs1(int x)
    {
        dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(int i = last[x]; i; i = e[i].next)
        {int y = e[i].to; if(y == fa[x]) continue;fa[y] = x; dfs1(y); siz[x] += siz[y]; siz[y] > siz[son[x]] ? son[x] = y : 0;}
    }
    void dfs2(int x)
    {
        rebeg[beg[x] = ++timer] = x; top[x] = son[fa[x]]==x?top[fa[x]]:x; if(son[x]) dfs2(son[x]);
        for(int i = last[x]; i; i = e[i].next){int y = e[i].to; if(y == son[x] || y == fa[x]) continue;dfs2(y);}end[x] = timer;
    }

    struct seg
    {
        int siz[2], siz_bla[2], rev[2]; ll mod[2], val;
    }t1[N*5], t2[N*5];
    /***************************************************************************************************************/
    void pushup1(int x)
    {
        seg *ls = &t1[x<<1], *rs = &t1[x<<1|1];
        for(int i = 0; i != 2; i++)
        {
            t1[x].siz[i] = ls->siz[i] + rs->siz[i];
            t1[x].siz_bla[i] = ls->siz_bla[i] + rs->siz_bla[i];
        }
    }
    void pushdown1(int x)
    {
        seg *ls = &t1[x<<1], *rs = &t1[x<<1|1];
        for(int i = 0; i != 2; i++) if(t1[x].rev[i])
        {
            ls->siz_bla[i] = ls->siz[i] - ls->siz_bla[i], rs->siz_bla[i] = rs->siz[i] - rs->siz_bla[i];
            ls->rev[i] ^= 1, rs->rev[i] ^= 1, t1[x].rev[i] = 0;
        }
    }
    void build1(int x, int l, int r)
    {
        t1[x].rev[0] = t1[x].rev[1] = 0;
        if(l == r)
        {
            int id = rebeg[l], d = (dep[id]&1);
            t1[x].siz[d] = 1;                   t1[x].siz[!d] = 0;
            t1[x].siz_bla[d] = c[id];           t1[x].siz_bla[!d] = 0;
            return;
        }
        int mid = (l+r)>>1; build1(x<<1,l,mid); build1(x<<1|1,mid+1,r); pushup1(x);
    }
    int query1_siz_bla(int x, int l, int r, int ql, int qr, int d)
    {
        if(ql <= l && r <= qr) return t1[x].siz_bla[d]; int mid = (l+r)>>1, ret = 0; pushdown1(x);
        if(ql <= mid) ret += query1_siz_bla(x<<1,l,mid,ql,qr,d); if(mid1|1,mid+1,r,ql,qr,d); return ret;
    }
    int query1_siz_bla(int x, int l, int r, int ql, int qr)
    {
            if(ql <= l && r <= qr) return t1[x].siz_bla[0]+t1[x].siz_bla[1]; int mid = (l+r)>>1, ret = 0; pushdown1(x);
        if(ql <= mid) ret += query1_siz_bla(x<<1,l,mid,ql,qr); if(mid1|1,mid+1,r,ql,qr); return ret;
    }
    int query1_siz(int x, int l, int r, int ql, int qr, int d)
    {
        if(ql <= l && r <= qr) return t1[x].siz[d]; int mid = (l+r)>>1, ret = 0; pushdown1(x);
        if(ql <= mid) ret += query1_siz(x<<1,l,mid,ql,qr,d); if(mid1|1,mid+1,r,ql,qr,d); return ret;
    }
    void modi1(int x, int l, int r, int ql, int qr, int d)
    {
        if(ql <= l && r <= qr) {t1[x].rev[d] ^= 1; t1[x].siz_bla[d] = t1[x].siz[d] - t1[x].siz_bla[d]; return;} int mid = (l+r)>>1;
        pushdown1(x); if(ql <= mid) modi1(x<<1,l,mid,ql,qr,d); if(mid < qr) modi1(x<<1|1,mid+1,r,ql,qr,d); pushup1(x);      
    }
    /***************************************************************************************************************/
    void pushup2(int x)
    {
        seg *ls = &t2[x<<1], *rs = &t2[x<<1|1];
        for(int i = 0; i != 2; i++)
        {
            t2[x].siz[i] = ls->siz[i] + rs->siz[i];
            t2[x].siz_bla[i] = ls->siz_bla[i] + rs->siz_bla[i];
            t2[x].mod[i] = ls->mod[i] + rs->mod[i];
            t2[x].val = ls->val + rs->val;
        }
    }
    void pushdown2(int x)
    {
        seg *ls = &t2[x<<1], *rs = &t2[x<<1|1];
        for(int i = 0; i != 2; i++) if(t2[x].rev[i])
        {
            ls->siz_bla[i] = ls->siz[i] - ls->siz_bla[i], rs->siz_bla[i] = rs->siz[i] - rs->siz_bla[i];
            ls->rev[i] ^= 1, rs->rev[i] ^= 1, t2[x].rev[i] = 0;
            ls->val += ls->mod[i], rs->val += rs->mod[i];
            ls->mod[i] *= -1, rs->mod[i] *= -1;
        }
    }
    void build2(int x, int l, int r)
    {
        t2[x].rev[0] = t2[x].rev[1] = 0;
        if(l == r)
        {
            int id = rebeg[l], d = (dep[id]&1);
            t2[x].siz[d] = 1; t2[x].siz[!d] = 0;
            t2[x].siz_bla[d] = query1_siz_bla(1,1,n,beg[id],beg[id]); 
            t2[x].siz_bla[!d] = 0;
            for(int i = last[id]; i; i = e[i].next)
            {
                int y = e[i].to; if(y == son[id] || y == fa[id]) continue;
                t2[x].siz[d] += query1_siz(1,1,n,beg[y],end[y],d);
                t2[x].siz[!d] += query1_siz(1,1,n,beg[y],end[y],!d); 
                t2[x].siz_bla[d] += query1_siz_bla(1,1,n,beg[y],end[y],d);
                t2[x].siz_bla[!d] += query1_siz_bla(1,1,n,beg[y],end[y],!d);
            }
            t2[x].mod[d] = (t2[x].siz[d] - 2ll * t2[x].siz_bla[d]) * id;
            t2[x].mod[!d] = (t2[x].siz[!d] - 2ll * t2[x].siz_bla[!d]) * id;
            t2[x].val = (ll)(t2[x].siz_bla[d] + t2[x].siz_bla[!d]) * id;
            return;
        }
        int mid = (l+r)>>1; build2(x<<1,l,mid); build2(x<<1|1,mid+1,r); pushup2(x);
    }
    ll query2(int x, int l, int r, int ql, int qr)
    {
        if(ql <= l && r <= qr) return t2[x].val; int mid = (l+r)>>1; ll ret = 0; pushdown2(x);
        if(ql <= mid) ret += query2(x<<1,l,mid,ql,qr); if(mid < qr) ret += query2(x<<1|1,mid+1,r,ql,qr); return ret;
    }
    void modi2(int x, int l, int r, int ql, int qr, int d)
    {
        if(ql <= l && r <= qr) 
        {
            t2[x].siz_bla[d] = t2[x].siz[d] - t2[x].siz_bla[d];
            t2[x].rev[d] ^= 1;
            t2[x].val += t2[x].mod[d];
            t2[x].mod[d] *= -1;
            return;
        }
        int mid = (l+r)>>1; pushdown2(x); 
        if(ql <= mid) modi2(x<<1,l,mid,ql,qr,d); if(mid < qr) modi2(x<<1|1,mid+1,r,ql,qr,d); pushup2(x);
    }
    void update2(int x, int l, int r, int p)
    {
        if(l == r) {build2(x,l,r); return;} int mid = (l+r)>>1; pushdown2(x);
        if(p <= mid) update2(x<<1,l,mid,p); else update2(x<<1|1,mid+1,r,p); pushup2(x);
    }
    /***************************************************************************************************************/
    void main()
    {
        n = read(), m = read();
        for(int i = 1; i <= n; i++) c[i] = read();
        for(int i = 1, a, b; i <  n; i++)
            addedge(a = read(), b = read()), addedge(b,a);
        dfs1(1); dfs2(1); build1(1,1,n); build2(1,1,n);
        for(int t = 1, op, x; t <= m; t++)
        {
            op = read(), x = read();
            if(op == 1)
            {
                int d = (dep[x]&1)^1;
                modi1(1,1,n,beg[x],end[x],d);
                for(int tmp = top[x]; fa[tmp]; tmp = top[fa[tmp]]) update2(1,1,n,beg[fa[tmp]]);
                modi2(1,1,n,beg[x],end[x],d);
            }
            else if(op == 2)
            {
                int d = (dep[x]&1);
                modi1(1,1,n,beg[x],beg[x],d); update2(1,1,n,beg[x]);
                for(int tmp = top[x]; fa[tmp]; tmp = top[fa[tmp]]) update2(1,1,n,beg[fa[tmp]]);
            }
            else 
            {
                ll ans = (ll)x * query1_siz_bla(1,1,n,beg[x],end[x]);
                for(int tmp = x, son = x; tmp; tmp = fa[son = top[tmp]])
                {
                    if(tmp != x) ans += (ll)tmp * (query1_siz_bla(1,1,n,beg[tmp],end[tmp]) - query1_siz_bla(1,1,n,beg[son],end[son]));
                    if(tmp != top[tmp]) ans += query2(1,1,n,beg[top[tmp]],beg[tmp]-1);
                }
                printf("%lld\n",ans);
            }
        }
    }
}
int main()
{
    runzhe2000::main();
}

你可能感兴趣的:(系列套题)