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