18-2-08 刷题心得

本来早上在bz随机了3道题,打算用5个小时做一做,结果一道树链剖分就卡了我3h多,还一道主席树发现我只会个板子,实际上完全不理解,遂切到洛谷温习数据结构;
这一天颓了好几个小时,总共就做了3道题+2道树状数组的板子题(没错我到现在才学会树状数组,之前一直用线段树)
本来是要把树状数组套主席树给做了的,一直理解不能,也就只能留到以后了0.0;

T1题目:bzoj 3999 旅游
一道几乎裸的树链剖分,处理好方向和一些细节后就没了;
我遇到的唯二坑点是:
①最后在同一条重链的时候,两边的点都是没有修改过的,大概是我树剖掌握的不扎实吧orz
②要算好空间!!!线段树开4倍!!!!!!!!!!!!!!!!!!!!
代码:

#include<cstdio>
#include<algorithm>
const int maxn=1005;
using std::max;
using std::min;
int t,n,m,hp,mp,sp,dhp,dmp,dsp,x;
int DP[maxn][maxn];
struct asd
{
    int xh,ct;
};
asd b[11];
asd c[11];
void dtgh(int N,int sh,int hf,int maxp,asd *a,int num,int *ans)
{
    for(int i=0;i<=N;i++)
    {
        ans[i]=0;
        for(int j=0;j<=maxp;j++)
            DP[i][j]=0;
    }
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<=maxp;j++)
        {
            for(int k=0;k<=num;k++)
                if(k==0)
                {
                    int tmp=j+hf;
                    if(tmp>maxp)tmp=maxp;
                    DP[i+1][tmp]=max(DP[i][j]+sh,DP[i+1][tmp]);
                }
                else if(j>=a[k].xh)
                    DP[i+1][j-a[k].xh]=max(DP[i+1][j-a[k].xh],DP[i][j]+a[k].ct);
            ans[i]=max(ans[i],DP[i][j]);
        }
    }
    for(int i=0;i<=maxp;i++)ans[N]=max(ans[N],DP[N][i]);
}
int ai[maxn];
int ans1[maxn],ans2[maxn];
int bld[maxn][maxn];
int tim[maxn];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d%d%d%d%d%d",&n,&m,&hp,&mp,&sp,&dhp,&dmp,&dsp,&x);
        for(int i=1;i<=n;i++)scanf("%d",&ai[i]);
        int tmp;
        scanf("%d",&tmp);
        for(int i=1;i<=tmp;i++)scanf("%d%d",&b[i].xh,&b[i].ct);
        dtgh(n,0,dmp,mp,b,tmp,ans1);
        scanf("%d",&tmp);
        for(int i=1;i<=tmp;i++)scanf("%d%d",&c[i].xh,&c[i].ct);      
        dtgh(n,x,dsp,sp,c,tmp,ans2);
        int flag=0;
        int rhp=hp;
        tim[0]=0;
        for(int i=0;i<=n;i++)tim[i]=n+1;
        for(int i=0;i<=n;i++)
        for(int j=0;j<=hp;j++)bld[i][j]=n+1;
        bld[0][hp]=0;
        for(int i=0;i<n;i++)
        {
            for(int j=1;j<=hp;j++)
            {
                int tmp=j-ai[i+1];
                if(tmp>0)
                bld[i+1][tmp]=min(bld[i+1][tmp],bld[i][j]);
                if(j!=hp)
                {
                    tmp=j+dhp;
                    if(tmp>hp)tmp=hp;
                    tmp-=ai[i+1];
                    if(tmp>0)
                    bld[i+1][tmp]=min(bld[i+1][tmp],bld[i][j]+1);
                }
                tim[i]=min(tim[i],bld[i][j]);
            }
        }
        for(int i=1;i<=hp;i++)tim[n]=min(tim[n],bld[n][i]);
        for(int i=1;i<=n;i++)
        {   
            int tmpsh=0;
            for(int k=0;k<=i-tim[i-1];k++)
                tmpsh=max(ans1[k]+ans2[i-tim[i-1]-k],tmpsh);
            if(m<=tmpsh)
            {
                printf("Yes %d\n",i);
                flag=1;
                break;
            }
            if(tim[i]>i)
            {
                printf("No\n");
                flag=1;
                break;
            }       
        }
        if(!flag)printf("Tie\n");   
    }
    return 0;
}

T2题目:bzoj 2588 count on a tree
树上的主席树,为了做我随机出来的那道题学了一天相关姿势;
理解了序列上的主席树这应该很好写,大体思路都一样;
不过,我很脑残的把序列离散化之后n被改变而没有记录,这样导致答案不对莫名re。。。
还有,bz评测的时候最后一个答案不能有空格!!!而且我还得把每个答案记下来一次性输出才能过。。。
代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
#define LL long long
#define random(a,b) (a+rand()%(b-a+1))
const int maxn=100005;
int n,m;
int node[maxn];
int a[maxn],b[maxn];
int dp[maxn][18];
int d[maxn];
int root[maxn]; 
int ans[maxn];
struct asd
{
    int next,to;
}edge[maxn*2];
struct qwe
{
    int l,r,sum;
}t[maxn*40];
int etot=0;
void add(int x,int y)
{
    edge[++etot].next=node[x];
    node[x]=etot;
    edge[etot].to=y;
}
int ntot=0;
void build(int l,int r,int &x,int y,int v)
{
    t[++ntot]=t[y],x=ntot,t[x].sum++;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(v<=mid)build(l,mid,t[x].l,t[y].l,v);
    else if(v>mid)build(mid+1,r,t[x].r,t[y].r,v); 
}
void dfs(int x,int fa)
{
    dp[x][0]=fa;
    d[x]=d[fa]+1;
    build(1,n,root[x],root[fa],std::lower_bound(a+1,a+n+1,b[x])-a);
    for(int i=node[x];i;i=edge[i].next)
        if(edge[i].to!=fa)dfs(edge[i].to,x);
}
int getlca(int x,int y)
{
    if(d[x]<d[y])std::swap(x,y);
    for(int i=17;i>=0;i--)
            if(d[dp[x][i]]>=d[y])x=dp[x][i];
    if(x==y)return x;   
    for(int i=17;i>=0;i--)
        if(dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];
    return dp[x][0]; 
} 
int query(int l,int r,int x,int y,int z1,int z2,int v)
{
    int tsum=0;
    while(l!=r) 
    {
        int mid=(l+r)>>1; 
        tsum=t[t[x].l].sum+t[t[y].l].sum-t[t[z1].l].sum-t[t[z2].l].sum;
        if(tsum>=v)x=t[x].l,y=t[y].l,z1=t[z1].l,z2=t[z2].l,r=mid;
        else x=t[x].r,y=t[y].r,z1=t[z1].r,z2=t[z2].r,l=mid+1,v-=tsum;
    }
    return l;
}
int main()
{
    scanf("%d%d",&n,&m);
    int rn=n;//不要忘了把n记录下来
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);      
        b[i]=a[i];  
    }
    for(int i=1;i<n;i++)
    {
        int tmp1,tmp2;
        scanf("%d%d",&tmp1,&tmp2);
        add(tmp1,tmp2);
        add(tmp2,tmp1);
    }
    std::sort(a+1,a+n+1);
    n=std::unique(a+1,a+n+1)-a-1;
    dfs(1,0);
    for(int i=1;i<=17;i++)
    for(int k=1;k<=rn;k++)dp[k][i]=dp[dp[k][i-1]][i-1];//这里用到的是n原来的值
    int up=0,tl,tr,tk;
    root[0]=t[0].l=t[0].r=t[0].sum=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&tl,&tr,&tk);
        tl^=up;
        int lca=getlca(tl,tr);
        ans[i]=up=a[query(1,n,root[tl],root[tr],root[lca],root[dp[lca][0]],tk)];
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d",ans[i]); 
        if(i!=m)printf("\n");
     } 
    return 0;
} 

T3题目:bzoj 1066 蜥蜴
这是我为数不多能建出模的网络流题,把每个柱子拆成两个点,一个入点一个出点,入到出的流量是柱子的高度,然后由源点到由蜥蜴的起点连为1的边,能够到达的柱子之间连inf的边,能出边界的边与汇点连inf的边(注意细节,我脑残的边界算错gg),然后跑一遍dinic就好了,这其中能够起限制作用的主要就是每个柱子拆成的两个点;
这题我tm又开小数组调了半天,怎么就是没记性呢!

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
#include<cctype>
#define LL long long
#define inf (1e9+7)
#define random(a,b) (a+rand()%(b-a+1))
int n,m,di;
int mapp[30][30];
int node[1005];
struct asd
{
    int x,y;
    asd()
    {
        x=y=0;
    }
    asd(int p1,int p2)
    {
        x=p1,y=p2;
    }
}q[505];
struct qwe
{
    int next,val,to,rev;
}edge[1000005];
int etot=0;
void add(int x,int y,int v)
{
    edge[++etot].next=node[x];
    node[x]=etot;
    edge[etot].to=y;
    edge[etot].val=v;
    if(v)edge[etot].rev=etot+1,add(y,x,0);
    else edge[etot].rev=etot-1;
} 
int ltot=0,ans=0;
int tot=0;
int que[1005];
int tail,head;
int d[1005];
int end;
bool bfs()
{
    for(int i=0;i<=end;i++)d[i]=0; 
    tail=head=0;
    que[tail++]=0;
    d[0]=1;
    while(head<tail)
    {
        int now=que[head++];
        for(int i=node[now];i;i=edge[i].next)
        {
            if(!d[edge[i].to]&&edge[i].val>0)
            {
                d[edge[i].to]=d[now]+1;
                if(edge[i].to==end)return true;
                que[tail++]=edge[i].to;
            }
        }
    }
    return false;
}
int dfs(int x,int low)
{
    if(x==end)return low;
    int rest=low;
    for(int i=node[x];i;i=edge[i].next)
    {
        if(d[edge[i].to]==d[x]+1&&edge[i].val>0&&rest)
        {
            int clow=dfs(edge[i].to,std::min(edge[i].val,rest));
            rest-=clow;
            edge[i].val-=clow;
            edge[edge[i].rev].val+=clow;
        }
    }
    return low-rest;
}
void dinic()
{
    while(bfs())
        ans+=dfs(0,inf);
}
int dis2(asd a,asd b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) ;
}
int main()
{
    scanf("%d%d%d",&n,&m,&di);
    char c;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        c=getchar();
        while(!isdigit(c))c=getchar();
        mapp[i][j]=c-'0';
        if(mapp[i][j])
            q[++tot]=asd(i,j);
    }
    end=tot*2+1;
    int d2=di*di;
    for(int i=1;i<=tot;i++)
        add(i,i+tot,mapp[q[i].x][q[i].y]);
    for(int i=1;i<=tot;i++)
    {
        if(q[i].x<=di||q[i].y<=di||n-q[i].x<di||m-q[i].y<di)//注意边界
            add(i+tot,end,inf);
        for(int j=i+1;j<=tot;j++)
        if(dis2(q[i],q[j])<=d2)
        {
            add(i+tot,j,inf);
            add(j+tot,i,inf);
        }
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        c=getchar();
        while(c!='.'&&c!='L')c=getchar();
        if(c=='L')
        for(int k=1;k<=tot;k++)
        if(q[k].x==i&&q[k].y==j)
        {
            ltot++;
            add(0,k,1);
            break;
        }
    }
    dinic();
    printf("%d",ltot-ans);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值