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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章