本來早上在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);
}