noip2016(tg)题解

D1T1:模拟不解释

D1T2:最难一题(真心不科学),考场上写了个nlog2n算法,当时还天真地以为只有一个log(手动滑稽),然而内存没开够(虽然官方数据似乎还是95)。

不过miaom大一眼帮我改到nlogn,说实话感觉比标解好理解多了。

首先树链剖分一发。然后起点到终点的路径就被pou成了logn段,这时就想着把这一段的时间(显然是一个+1/-1等差数列)变成一个数,然后我想的是把他们的时间全部减去他们的dfn序号(-1的就反过来,可以自己yy一下),然后就将操作变成了在[l,r]这段上将权值为k的每一个数值加1(数值不是权值),然后差分一下,最后乱搞前缀和就行了。。。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define gc getchar()
#define N 1000059
#define mid (l+r>>1)
#define pa pair<int,int>
using namespace std;
int n,m,first[N],number=0,x,y,w[N],s[N],t[N],cnt=0,Cnt=0;
int father[N],size[N],Mson[N],deep[N],dfn[N],top[N],Id[N];
int ans[N],aaa[N][2],val[N][2];
vector<pa> an[N][2];
struct edge
{
    int to,next;
    void add(int x,int y)
    {
        to=y,next=first[x],first[x]=number;
    }
}e[N<<1];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch>'9'||ch<'0') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
void dfs1(int x)
{
    size[x]=1;
    deep[x]=deep[father[x]]+1;
    for (int i=first[x];i;i=e[i].next)
        if (e[i].to!=father[x])
        {
            father[e[i].to]=x;
            dfs1(e[i].to);
            size[x]+=size[e[i].to];
            if (size[e[i].to]>size[Mson[x]]) Mson[x]=e[i].to;
        }
}
void dfs2(int x,int y)
{
    top[x]=y;
    dfn[x]=++cnt;
    Id[cnt]=x;
    if (Mson[x]) dfs2(Mson[x],y);
    for (int i=first[x];i;i=e[i].next)
        if (e[i].to!=father[x]&&e[i].to!=Mson[x])
            dfs2(e[i].to,e[i].to);
}
int lca(int x,int y)
{
    for (;top[x]!=top[y];x=father[top[x]])
        if (deep[top[x]]<deep[top[y]]) swap(x,y);
    return deep[x]<deep[y]?x:y;
}
int get_dis(int x,int y)
{
    return deep[x]+deep[y]-2*deep[lca(x,y)];
}
void ins(int l,int r,int val,int k)
{
    an[l][k].push_back(make_pair(val,1));
    an[r+1][k].push_back(make_pair(val,-1));
}
void ins(int x,int y)
{
    int pd=1;
    int st=0;
    int dis=get_dis(x,y);
    for (;top[x]!=top[y];x=father[top[x]])
    {
        if (deep[top[x]]<deep[top[y]]) swap(x,y),pd^=1;
        if (pd==1)
        {
            ins(dfn[top[x]],dfn[x],st+dfn[x]-1,1);
            st+=dfn[x]-dfn[top[x]]+1;
        }
        else
        {
            ins(dfn[top[x]],dfn[x],dis-dfn[x]+n,0);
            dis-=(dfn[x]-dfn[top[x]])+1;
        }
    }
    if (dfn[x]>dfn[y]) swap(x,y),pd^=1;
    if (pd==1)
        ins(dfn[x],dfn[y],st-dfn[x]+n,0);
    else
        ins(dfn[x],dfn[y],st+dfn[y]-1,1);
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<n;i++)
    {
        x=read(),y=read();
        e[++number].add(x,y);
        e[++number].add(y,x);
    }
    father[1]=deep[0]=0;
    dfs1(1);
    dfs2(1,1);
    for (int i=1;i<=n;i++)
        w[i]=read();
    for (int i=1;i<=m;i++)
    {
        s[i]=read(),t[i]=read();
        ins(s[i],t[i]);
    }
    for (int l=1;l<=n;l++)
    {
        val[l][0]=w[Id[l]]-l+n;
        val[l][1]=w[Id[l]]+l-1;
    }
    memset(aaa,0,sizeof(aaa));
    for (int i=1;i<=n;i++)
    {
        for (int k=0;k<2;k++)
            for (int j=0;j<an[i][k].size();j++)
                aaa[an[i][k][j].first][k]+=an[i][k][j].second;
        ans[Id[i]]=aaa[val[i][0]][0]+aaa[val[i][1]][1];
    }
    for (int i=1;i<=n;i++)
        printf("%d%s",ans[i],i==n?"\n":" ");
    return 0;
}
D1T3:斯波的期望打牌(dp),然后我忘了初始化了,始化了,化了,了,。。。。

dp[i][j][k]表示第i个教室是否申请,然后总共申请了k次的期望路径值。。。

D2T1:这都能炸,感觉人生没有希望。。预处理出2000*2000的c值(杨辉三角),然后二维前缀和一发

D2T2:看出来单调性后本题也变成了斯波题。。每条蚯蚓增加,相当于没有加的两条(刚断的)减去增加量。然后三个单调队列搞一搞,常数注意一下就行

D3T3:Tn2^ndp或者传说中的暴力dfs就能过,n^3预处理出选择两只猪后能打到哪些猪(状态压缩),然后状压dp一发就OK。。

似乎只有D1T2可以说一下。。然而一片斯波错误。。轻易滚粗。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值