首先是 Buildings
题目大概:
这道题是给出n,m,是一个矩形的大小,然后有一个地块x,y不能填矩形,问,如果用小矩形填满这个大矩形,使得最大的小矩形最小的填法,这个矩形大小是多少。
思路:
首先这个矩形一定是宽度为1,才最小而且符合题目要求。
这个题可以观察题目给出的样例,可以得知,就是求解 x,y 四周的这四个矩形填满 应该需要多大的矩形,取最小值。然后就是不管有没有这个x,y,直接用(n+1)/2,来整体求这个大矩形的最小值。
具体的如果n,m为奇数,而且x,y在中央,那么应该是n/2需要特判。
感想:
一般这种找规律的题,首先要从样例出发,找出规律,然后具体的特例需要自己造数据。
一般这种构造类型的题,需要自己取找构造的点,就是受题目限制很大的点,根据这些要点来构造,比如这里,x,y这个矩形的四周就是这个要点。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,x,y;
int main()
{
while(scanf("%d%d%d%d",&n,&m,&x,&y)!=EOF)
{
if(n>m)
{
swap(n,m);
swap(x,y);
}
if(n==m&&n%2==1&&x==(n+1)/2&&y==(m+1)/2)
{
printf("%d\n",n/2);
continue;
}
int mi_1=min(x-1,min(y,m-y+1));
int mi_2=min(n-x,min(y,m-y+1));
int ans=(n+1)/2;
int sum=max(mi_1,max(mi_2,ans));
printf("%d\n",sum);
}
return 0;
}
Gorgeous Sequence
题目大概:
给出n个数,然后给出3中操作
0 把 区间 l r 的比v大的值改成v。
1 求区间 l r 的最大值。
2 求区间 l r 的和。
思路:
这个题的1 2操作都是线段树的基本操作,但是0操作有些复杂,如果直接修改,时间上会受不了。就采用了吉如一的线段树操作。维护最大值,次大值,最大值数量。这样在次大值<v<最大值的时候,就可以很快的把最大值都修改成 v,并用懒惰标记标记一下,这样维护后,对于修改后,最大值,次大值,最大值数量的维护,和的维护,都比较容易求解。
感想:
这样的维护,就把很多必须深入修改的东西,统一了起来。因为每次修改,修改到一定层数,一定会出现思路中讲到的修改方式,以此来进行懒惰修改,节约时间。这一点一定要借鉴学习,以后需要类似的问题,要转化成可以标记懒惰数组的形式。
代码:
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=1e6+10;
int n,m;
long long sum[maxn];
int max_1[maxn],max_2[maxn];
int maxsum[maxn];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
max_1[rt]=max(max_1[rt<<1],max_1[rt<<1|1]);
maxsum[rt]=0;
max_2[rt]=max(max_2[rt<<1],max_2[rt<<1|1]);
if(max_1[rt]==max_1[rt<<1])
{
maxsum[rt]+=maxsum[rt<<1];
}
else max_2[rt]=max(max_1[rt<<1],max_2[rt]);
if(max_1[rt]==max_1[rt<<1|1])
{
maxsum[rt]+=maxsum[rt<<1|1];
}
else max_2[rt]=max(max_1[rt<<1|1],max_2[rt]);
}
void pushdown(int rt)
{
if(max_1[rt]<max_1[rt<<1])
{
sum[rt<<1]-=(long long)maxsum[rt<<1]*(max_1[rt<<1]-max_1[rt]);
max_1[rt<<1]=max_1[rt];
}
if(max_1[rt]<max_1[rt<<1|1])
{
sum[rt<<1|1]-=(long long)maxsum[rt<<1|1]*(max_1[rt<<1|1]-max_1[rt]);
max_1[rt<<1|1]=max_1[rt];
}
}
void build(int l,int r,int rt)
{
if(l==r)
{
scanf("%I64d",&sum[rt]);
max_1[rt]=sum[rt];
max_2[rt]=-1;
maxsum[rt]=1;
return;
}
int m=(l+r)/2;
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,int v,int l,int r,int rt)
{
if(v>=max_1[rt])return;
if(L<=l&&r<=R&&max_2[rt]<v)
{
sum[rt]-=(long long)maxsum[rt]*(max_1[rt]-v);
max_1[rt]=v;
return;
}
pushdown(rt);
int m=(l+r)/2;
if(m>=L)update(L,R,v,lson);
if(m<R)update(L,R,v,rson);
pushup(rt);
}
int getmax(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return max_1[rt];
}
pushdown(rt);
int m=(l+r)/2;
int ans=0;
if(L<=m)ans=max(ans,getmax(L,R,lson));
if(m<R)ans=max(ans,getmax(L,R,rson));
return ans;
}
long long getsum(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return sum[rt];
}
pushdown(rt);
int m=(l+r)/2;
long long ans=0;
if(L<=m)ans+=getsum(L,R,lson);
if(m<R)ans+=getsum(L,R,rson);
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,n,1);
while(m--)
{
int flag;
scanf("%d",&flag);
if(flag==0)
{
int l,r,v;
scanf("%d%d%d",&l,&r,&v);
update(l,r,v,1,n,1);
}
else if(flag==1)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",getmax(l,r,1,n,1));
}
else
{
int l,r;
scanf("%d%d",&l,&r);
printf("%I64d\n",getsum(l,r,1,n,1));
}
}
}
return 0;
}