据说是老师自己翻译的……虽然全是粘的题2333
Q1
描述:
农夫John有N头牛,将牛从1到N编号。经过测试,每头牛有一个测试值[Si, Ei].有的牛强壮,有的牛虚弱。给两头牛i和j,如果Si <= Sj ,Ej <= Ei 并且 Ei - Si > Ej - Sj, 那么我们认为牛i比牛j强壮。
问对于每头牛,有多少牛比它强壮.
输入:
第一行,一个整数N, 表示牛的头数。
接下来N行, 每行两个整数, Si, Ei, 表示第i头牛的测试值。(0 <= Si < Ei <= 10^5)
(OJ上多case,以N=0结束)
输出:
输出N个整数,用空格分开,第i个整数表示有多少牛比第i头牛强壮。
样例输入:
3
1 2
0 3
3 4
样例输出:
1 0 0
数据范围:
30%数据, 1 <= N <= 10^3
100%数据,1 <= N <= 10^5
地址:
http://bailian.openjudge.cn/practice/2481
思路:
1)显然,有Si<=Sj, Ej<=Ei 可以推得出来第三个式子只在两只牛两个值都相同的时候才有用
于是双关键字(Si<Sj, Ei>Ej) 排序,每只牛只影响它后面的,而且数据范围表示并不用离散化
呆马↓
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std; int n;
struct t1{
int S,E;
int lab;
bool operator < (const t1 x)const {
return S==x.S?E>x.E:S<x.S;
}
}dt[100057];
int lzy[500557];
void pushdown(int now){
lzy[now<<1]+=lzy[now],lzy[now<<1|1]+=lzy[now];
lzy[now]=0;
}
void modify(int now,int l,int r,int L,int R){
if(!(~R)) return;
if(L<=l&&r<=R){
++lzy[now];
return ;
}
if(lzy[now]) pushdown(now);
int mid=(l+r)>>1;
if(L<=mid) modify(now<<1,l,mid,L,R);
if(mid<R) modify(now<<1|1,mid+1,r,L,R);
}
int inqry(int now,int l,int r,int loc){
if(r==l)
return lzy[now];
pushdown(now);
int mid=(l+r)>>1;
if(loc<=mid) inqry(now<<1,l,mid,loc);
else inqry(now<<1|1,mid+1,r,loc);
}
int ans[100057];
int mx=0;
int main(){
memset(dt,0,sizeof(dt));
memset(lzy,0,sizeof(lzy));
freopen("in","r",stdin);
freopen("out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d",&dt[i].S,&dt[i].E);
dt[i].lab=i;
mx=max(mx,dt[i].E);
}
sort(dt+1,dt+n+1);
for(int i=1;i<=n;++i){
if(dt[i].E==dt[i-1].E&&dt[i].S==dt[i-1].S)
ans[dt[i].lab]=ans[dt[i-1].lab];
else
ans[dt[i].lab]=inqry(1,0,mx,dt[i].E);
modify(1,0,mx,0,dt[i].E);
}
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
return 0;
}
Q2
描述:
在大选中,政府建立了一堵墙给n个候选人贴海报。
每张海报的高和墙一样高,占据一段连续的墙,并且起点和终点都是整数。
每位候选人依次贴海报,后面贴的海报会覆盖前面贴的海报,问最后能看到几个人的海报?
输入
第一行是case数T,对于每个case:
第一行一个整数n(n <= 10000), 表示候选人数。
接下来n行,每行两个整数l_i, r_i, 表示第i位候选人贴的海报占据的位置。(1 <= l_i <= r_i <= 10^7)
输出
输出最后能看见的海报数。
样例输入
1
5
1 4
2 6
8 10
3 4
7 10
样例输出
4
网址:
http://bailian.openjudge.cn/practice/2528
思路:
1)水题,但是老师改了数据范围于是跪了【线段树开小了,表示堆式的还是多开一点空间比较好orzorz
呆马↓
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std; int T,n;
const int MAXN=100057;
int l[MAXN],r[MAXN];
vector<int> mem;
int clr[MAXN];
int lzy[MAXN*5];
void pushdown(int now){
lzy[now<<1]=lzy[now<<1|1]=lzy[now];
lzy[now]=0;
}
void modify(int now,int ll,int rr,int L,int R,int q){
if(L<=ll&&rr<=R){
lzy[now]=q;
return ;
}
if(lzy[now]) pushdown(now);
int mid=(ll+rr)>>1;
if(L<=mid) modify(now<<1,ll,mid,L,R,q);
if(mid<R) modify(now<<1|1,mid+1,rr,L,R,q);
}
int tag[MAXN];
void doit(int now,int ll,int rr){
if(ll==rr){
tag[lzy[now]]=1;
return ;
}
if(lzy[now]) pushdown(now);
int mid=(ll+rr)>>1;
doit(now<<1,ll,mid);
doit(now<<1|1,mid+1,rr);
}
int main(){
freopen("in","r",stdin);
freopen("out","w",stdout);
scanf("%d",&T);
while(T--){
memset(lzy,0,sizeof(lzy));
memset(tag,0,sizeof(tag));
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d",&l[i],&r[i]);
mem.push_back(l[i]);
mem.push_back(r[i]);
}
sort(mem.begin(),mem.end());
unique(mem.begin(),mem.end());
for(int i=1;i<=n;++i){
l[i]=lower_bound(mem.begin(),mem.end(),l[i])-mem.begin()+1;
r[i]=lower_bound(mem.begin(),mem.end(),r[i])-mem.begin()+1;
}
int mx=mem.size();
mem.clear();
for(int i=1;i<=n;++i)
modify(1,1,mx,l[i],r[i],i);
doit(1,1,mx);
int cnt=0;
for(int i=1;i<=n;++i) if(tag[i]) ++cnt;
printf("%d\n",cnt);
}
return 0;
}
Q3
描述
一个平面上有若干整数坐标的点。
Stan和Ollie玩游戏,Stan首先画一条竖直线,这条竖直线必须经过平面上的某个点。 Ollie再画一条水平线,这条线必须经过Stan所画线所经过的其中一个点。
这样,平面被分为4个象限, Stan的得分为第一, 三象限中的点的个数, Ollie的得分为第二、四象限中的点的个数。 不计算所画线上的点。
Stan和Ollie想最大化他们的得分。Stan想最大化在最坏情况下的最高得分。
输入
多case。
每个case,第一行,一个整数n(1 < n < 2*10^5),表示平面上点的个数。
接下来n行,每行两个整数x, y, 表示每个点的坐标。没有两个点的坐标相同。
输入以n = 0结束
输出
对于每个case,输出一行(格式参看样例输出)。 第一个整数是Stan在最坏情况的最高得分, 其他的整数是Ollie的可能得分, 按增序输出。
样例输入
11
3 2
3 3
3 4
3 6
2 -2
1 -3
0 0
-3 -3
-3 -2
-3 -4
3 -7
0
样例输出
Stan: 7; Ollie: 2 3;
网址:
http://bailian.openjudge.cn/practice/2464/
思路:
null(x 【表示考试的时候浪的很开心orzorz这道题欢快地只是看了一眼233 回家再改