151216总结

TJOI2015 D2
T1
给一颗树,每次给出 A 、B ,求 A -> B 的路径上 max{aj - ai} (i 先于 j 经过),然后将A -> B 的路径上的点全部加上 v
裸的树链剖分,主要是线段树最大最小值的合并操作,线段树维护区间最大值、最小值、从左到右的最大差和从右到左的最大差,先求得两点的lca,再分别计算 x -> lca 和 lca -> y ,注意顺序不能写反。每次要询问完后,再修改,不然会Wa掉。
//代码能力还是不够,写了一天。。。

复杂度:O(Nlog^2N)

需要的知识:链剖

T2
看到这道题想到的肯定是状压DP,先预处理出每一种状态,然后验证当前状态合不合法,再求得每种状态能否转移到另一种状态。
得到状态转移方程
F[i, j] = F[i1k] (其中 a[j,k]=1 , 即 k 状态能转移到 j 状态) //写矩乘的时候写成了这样,-_-
这样的复杂度是 O(n * 2^m * 2^m),要T
然后发现每种转移都是一样的
然后设一个 tot * tot(状态数)的矩阵 a , aij 表示状态 j 能转移到状态 i ,tot * 1 的矩阵 b 表示初始状态,即F[0,0],然后矩阵快速幂

复杂度:O(logN * (2^m)^3)

需要的知识:状压dp,矩阵快速幂

T3
神一样的题(╯▽╰)
找到规律 ans = n*(n+1)/(4n-2)
证明:YYY第一定理

//其实不会啦~~

需要的知识:数学

贴代码
T1 bzoj3999

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#define N 50005
#define INF 100000000000
#define LL long long
using namespace std;

int n,m,Size,tot,x,y,k;LL c,minn,maxx,ans;
int first[N],next[N<<1],to[N<<1];
int father[N],son[N],d[N],w[N],top[N],size[N];
LL mx[N<<2],mn[N<<2],delt[N<<2][2],f[N<<2];
int a[N],b[N],p[N];

int get_int()
{
    int ret=0;char c=getchar();
    for (;c<'0'||c>'9';c=getchar());
    for (;c>='0'&&c<='9';c=getchar())
        ret=(ret<<1)+(ret<<3)+c-'0';
    return ret;
}

void inser(int x,int y)
{
    Size++;
    next[Size]=first[x];
    first[x]=Size;
    to[Size]=y;
}

void dfs1(int x)
{
    size[x]=1;
    for (int i=first[x];i;i=next[i])
    {
        int y=to[i];
        if (y!=father[x])
        {
            father[y]=x;
            d[y]=d[x]+1;
            dfs1(y);
            if (size[y]>size[son[x]])
                son[x]=y;
            size[x]+=size[y];
        }
    }
}

void dfs2(int x,int tp)
{
    top[x]=tp;
    w[x]=++tot;
    if (son[x]) dfs2(son[x],tp);
    for (int i=first[x];i;i=next[i])
    {
        int y=to[i];
        if (y!=father[x]&&y!=son[x])
            dfs2(y,y);
    }
}

void push_down(int v)
{
    if (!f[v]) return;
    int lc=v<<1,rc=v<<1|1;
    f[lc]+=f[v];
    f[rc]+=f[v];
    mx[lc]+=f[v];
    mx[rc]+=f[v];
    mn[lc]+=f[v];
    mn[rc]+=f[v];
    f[v]=0;
}

void update(int v)
{
    int lc=v<<1,rc=v<<1|1;
    mx[v]=max(mx[lc],mx[rc]);
    mn[v]=min(mn[lc],mn[rc]);
    delt[v][0]=max(max(delt[lc][0],delt[rc][0]),mx[rc]-mn[lc]);
    delt[v][1]=max(max(delt[lc][1],delt[rc][1]),mx[lc]-mn[rc]);
}

void build(int v,int l,int r)
{
    if (l==r)
    {
        mx[v]=mn[v]=b[l];
        return;
    }
    int mid=(l+r)>>1;
    build(v<<1,l,mid);
    build(v<<1|1,mid+1,r);
    update(v);
}

void init()
{
    int x,y;
    n=get_int();
    for (int i=1;i<=n;i++) a[i]=get_int();
    for (int i=1;i<n;i++)
    {
        x=get_int();y=get_int();
        inser(x,y);
        inser(y,x);
    }
    dfs1(1);
    dfs2(1,1);
    for (int i=1;i<=n;i++) b[w[i]]=a[i];
    build(1,1,n);
}

void modify(int v,int l,int r)
{
    if (x<=l&&r<=y) 
    {
        f[v]+=c;
        mn[v]+=c;
        mx[v]+=c;
        return;
    }
    int mid=(l+r)>>1;
    push_down(v);
    if (x<=mid) modify(v<<1,l,mid);
    if (mid<y) modify(v<<1|1,mid+1,r);
    update(v);
}

void add(int v,int u)
{
    int f1=top[v],f2=top[u];
    while (f1!=f2)
    {
        if (d[f1]<d[f2])
        {
            swap(f1,f2);
            swap(v,u);
        }
        x=w[f1],y=w[v],modify(1,1,n);
        v=father[f1],f1=top[v];
    }
    if (d[v]<d[u]) swap(v,u);
    x=w[u],y=w[v],modify(1,1,n);
}

int lca(int x,int y)
{
    while (top[x]!=top[y])
    {
        if (d[top[x]]<d[top[y]]) swap(x,y);
        x=father[top[x]];
    }
    return d[x]<d[y] ? x : y;
}

void ask(int v,int l,int r)
{
    if (x<=l&&r<=y)
    {
        ans=max(max(ans,delt[v][k]),mx[v]-minn);
        maxx=max(mx[v],maxx);
        minn=min(mn[v],minn);
        return;
    }
    int mid=(l+r)>>1;
    push_down(v);
    if (k){
        if (mid<y) ask(v<<1|1,mid+1,r);
        if (x<=mid) ask(v<<1,l,mid);
    }else {
        if (x<=mid) ask(v<<1,l,mid);
        if (mid<y) ask(v<<1|1,mid+1,r);
    }
    update(v);
}

void query(int v,int u)
{
    int z=lca(v,u);
    minn=INF,maxx=ans=0,k=1;
    while (top[v]!=top[z])
    {
        x=w[top[v]],y=w[v],ask(1,1,n);
        v=father[top[v]];
    }
    x=w[z],y=w[v],ask(1,1,n);
    tot=k=0;
    while (top[u]!=top[z])
    {
        p[++tot]=w[u];p[++tot]=w[top[u]];
        u=father[top[u]];
    }
    if (u^z) p[++tot]=w[u],p[++tot]=w[z];
    for (int i=tot;i;i-=2)
        x=p[i],y=p[i-1],ask(1,1,n);
}

int main()
{
    int v,u;
    init();
    m=get_int();
    for (int i=1;i<=m;i++)
    {
        v=get_int();u=get_int();c=get_int();
        query(v,u);
        printf("%lld\n",ans);
        add(v,u);
    }

    return 0;
}

T2 bzoj4000

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#define LL long long
using namespace std;

const LL M=(LL)(1ll<<32ll) - 1;
int n,m,k,p,tot;
int b[3],c[64];
LL a[64][64],ret[64][64],t[64][64];

bool judge(int x)
{
    for (int i=0,t=x;i<m;t>>=1,i++)
        if (t&1)
        {
            if (k>=i)
                if (x&(b[1]>>(k-i))) return 0;
            if (k<i)
                if (x&(b[1]<<(i-k))) return 0;
        }
    return 1;
}

int check(int x,int y)
{
    for (int i=0,t=x;i<m;t>>=1,i++)
        if (t&1)
        {
            if (k>=i)
                if (y&(b[2]>>(k-i))) return 0;
            if (k<i)
                if (y&(b[2]<<(i-k))) return 0;
        }
    for (int i=0,t=y;i<m;t>>=1,i++)
        if (t&1)
        {
            if (k>=i)
                if (x&(b[0]>>(k-i))) return 0;
            if (k<i)
                if (x&(b[0]<<(i-k))) return 0;
        }
    return 1;
}

void init()
{
    int x;
    scanf("%d%d",&n,&m);
    scanf("%d%d",&p,&k);
    k=p-k-1;
    for (int i=0;i<3;i++)
        for (int j=0;j<p;j++)
        {
            scanf("%d",&x);
            b[i]=b[i]<<1|x;
        }
    b[1]^=(1<<k);
    for (int i=0;i<(1<<m);i++)
        if (judge(i)) c[tot++]=i;
    for (int i=0;i<tot;i++)
        for (int j=0;j<tot;j++)
            a[j][i]=check(c[i],c[j]);
}

LL mult(LL m,LL n)
{
    LL a=m>>1,x=m-a,b=n>>1,y=n-b;
    return ((a*b)&M)+((a*y)&M)+((b*x)&M)+((x*y)&M);
}

void mul(LL a[][64],LL b[][64])
{
    for (int i=0;i<tot;i++)
        for (int j=0;j<tot;j++)
        {
            t[i][j]=0;
            for (int k=0;k<tot;k++)
                t[i][j]=(t[i][j]+mult(a[i][k],b[k][j]))&M;
        }
    for (int i=0;i<tot;i++)
        for (int j=0;j<tot;j++)
            a[i][j]=t[i][j];
}

void ksm(int b)
{
    for (int i=0;i<tot;i++) ret[i][i]=1;
    for (;b;b>>=1,mul(a,a))
        if (b&1) mul(ret,a);
}

int main()
{
    init();
    ksm(n);
    LL ans=0;
    for (int i=0;i<tot;i++)
        ans=(ans+ret[i][0])&M;
    cout<<ans<<endl;

    return 0;
}

T3 bzoj4001

#include<cstdio>
int main(){
    double n;
    scanf("%lf",&n);
    printf("%0.9f",n*(n+1)/(4*n-2));
    return 0;
}

YYY 就是神~

你可能感兴趣的:(总结)