第一题:
递交超链接((http://blog.csdn.net/qq_36038511/article/details/54561938))
第二题:
市长的海报(来源:POJ2528)
(posters.cpp)
【题意】
n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。
求出最后还能看见多少张海报。(注意:没多组数据)
代码:
#include
#include
#include
#include
using namespace std;
struct ls
{
int x,z,p;
}a[21000],b[21000];//离散化专用
int s[21000];
struct trnode
{
int l,r,c,lc,rc;
}tr[81000];int len;
bool v[11000];
int lscmp(const void *xx,const void *yy)//自定义快排
{
ls n1=*(ls *)xx;
ls n2=*(ls *)yy;
return n1.x-n2.x;
}
void bt(int l,int r)
{
len++;int now=len;
tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1; tr[now].c=0;
if(lint mid=(l+r)/2;
tr[now].lc=len+1;bt(l,mid);
tr[now].rc=len+1;bt(mid+1,r);
}
}
void change(int now,int l,int r,int k)
{
if(tr[now].c==k) return;
//如果当前这部分已经更新过了,就没有必要更新了(或者说已经贴了这张海报了)
if(tr[now].l==l && tr[now].r==r)
{
tr[now].c=k;
return;
}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
if(tr[now].c>=0)//lazy更新
{
tr[lc].c=tr[now].c;
tr[rc].c=tr[now].c;
}
if(r<=mid) change(lc,l,r,k);
else if(mid+1<=l) change(rc,l,r,k);
else
{
change(lc,l,mid,k);
change(rc,mid+1,r,k);
}
if(tr[lc].c==tr[rc].c) tr[now].c=tr[lc].c;
else tr[now].c=-1;
}
void query(int now,int l,int r)//查找贴过的海报
{
if(tr[now].c>=0){v[tr[now].c]=true;return;}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
if(r<=mid) query(lc,l,r);
else if(mid+1<=l) query(rc,l,r);
else
{
query(lc,l,mid);
query(rc,mid+1,r);
}
}
int main()
{
freopen("posters.in","r",stdin);
freopen("posters.out","w",stdout);
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[2*i-1].x,&a[2*i].x);
a[2*i-1].p=2*i-1;
a[2*i].p=2*i;
}
for(int i=1;i<=2*n;i++){b[i].x=a[i].x,b[i].p=a[i].p;}
qsort(b+1,2*n,sizeof(ls),lscmp);
b[1].z=1;
for(int i=2;i<=2*n;i++)
{
if(b[i].x==b[i-1].x) b[i].z=b[i-1].z;
else if(b[i].x-b[i-1].x==1) b[i].z=b[i-1].z+1;
else if(b[i].x-b[i-1].x>1) b[i].z=b[i-1].z+2;
}
for(int i=1;i<=2*n;i++) s[b[i].p]=b[i].z;
//以上为离散化
len=0;bt(1,b[2*n].z);
for(int i=1;i<=n;i++)change(1,s[2*i-1],s[2*i],i);
memset(v,false,sizeof(v));
query(1,1,b[2*n].z);
int ans=0;for(int i=1;i<=n;i++)if(v[i]==true)ans++;//累加能看到的海报
printf("%d\n",ans);
return 0;
}
推荐一个好的算法:
如果更新次数太多的话,可以考虑从后往前更新
即如果更新时发现之前已经有一张海报完全覆盖他了
就可以不用更新(因为没有必要)
这样的算法时间会减少很多
第三题:
A Line painting(来源:ural1019)
(bw.cpp)
【题目描述】
先是在数轴区间 0 到10^9 (10的9次方)之间画上了白色。然后,这个区间的某一些部分又画上了黑色。然后某一些部分又画上白色,等等。请你找出经历N(1 <= N <= 5000)次重着色后,最长的白色区间。
【输入格式】
首行位N,以下N行位重着色的信息,每一行格式如下:
ai bi ci 这里 ai ,bi 都是整数, ci 为字符’b’ 或’w’,用空格隔开。
这三个参数描述:从ai到bi,着颜色ci, (‘w’表示白,’b’表示黑),可以认为0 < ai <= bi < 10**9.
【输出格式】
输出x,y (x < y),之间用空格隔开,表示最长的白色区间。假如有多个答案,输出x最小的那个
代码:
#include
#include
#include
int len=0;
struct node{int l,r,lc,rc,c;bool update;};
struct paint{int a,b;char c;};
struct ls{int o,n;};
node t[20020];
paint p[10010];
ls pp[20020];
int ll=0;
int n;
void qsort(int l,int r)
{
int i,j;
int m;
ls t;
i=l;j=r;
m=pp[(i+j)>>1].o;
while (i<=j)
{
while (pp[i].o<m) i++;
while (pp[j].o>m) j--;
if (i<=j)
{
t=pp[i];pp[i]=pp[j];pp[j]=t;
i++;j--;
}
}
if (lif (iint wz(int x)
{
int l=1,r=ll,m;
while (1)
{
m=(l+r)>>1;
if (pp[m].o==x) break;
if (pp[m].o>x) r=m-1;
else l=m+1;
}
return pp[m].n;
}
int build(int l,int r)
{
len++;
int x=len;
t[x].l=l;t[x].r=r;t[x].c=0;t[x].update=false;
if (l+1!=r)
{
int mid;
mid=(l+r)>>1;
t[x].lc=build(l,mid);
t[x].rc=build(mid,r);
}
return x;
}
void update(int x)
{
t[x].update=false;
t[t[x].lc].update=true;
t[t[x].lc].c=t[x].c;
t[t[x].rc].update=true;
t[t[x].rc].c=t[x].c;
}
void insert(int x,int l,int r,int c)
{
if (t[x].l==l && t[x].r==r)
{
t[x].c=c;
t[x].update=true;
return;
}
int mid,lc,rc;
mid=(t[x].l+t[x].r)>>1;
lc=t[x].lc;rc=t[x].rc;
if (t[x].update) update(x);
if (r<=mid) insert(lc,l,r,c);
else if (mid<=l) insert(rc,l,r,c);
else
{
insert(lc,l,mid,c);
insert(rc,mid,r,c);}
if (t[lc].c==t[rc].c) t[x].c=t[lc].c;
else t[x].c=-1;
}
int getcount(int x,int l,int r)
{
if (t[x].l==l && t[x].r==r)
{
return t[x].c;
}
int mid,lc,rc;
mid=(t[x].l+t[x].r)>>1;
lc=t[x].lc;rc=t[x].rc;
if (t[x].update) update(x);
if (r<=mid) return getcount(lc,l,r);
if (mid<=l) return getcount(rc,l,r);
}
int main()
{
freopen("bw.in","r",stdin);
freopen("bw.out","w",stdout);
scanf("%d",&n);
pp[1].o=0;pp[2].o=1000000000;
ll=2;
for (int i=1;i<=n;i++)
{
scanf("%d %d %c",&p[i].a,&p[i].b,&p[i].c);
pp[++ll].o=p[i].a;pp[++ll].o=p[i].b;
getchar();
}
qsort(1,ll);
pp[1].n=1;
for (int i=2;i<=ll;i++)
{
if (pp[i].o==pp[i-1].o) pp[i].n=pp[i-1].n;
else pp[i].n=i;
}
build(1,ll);
for (int i=1;i<=n;i++)
{
if (p[i].a==p[i].b) continue;
//printf("%d %d\n",wz(p[i].a),wz(p[i].b));
insert(1,wz(p[i].a),wz(p[i].b),(p[i].c=='b'));
//printf("ok\n");
}
//printf("XX\n");
int now=0,ans=0,ansl,ansr,l=0,r=1;
for (int i=1;iif (getcount(1,i,i+1)==0) {r=pp[i+1].o;now=r-l;}
else {l=pp[i+1].o;now=0;}
if (now>ans) {ans=now;ansl=l;ansr=r;};
}
printf("%d %d",ansl,ansr);
}
儿童节快乐
(happy.cpp)
【描述】
儿童节即将到来。在这一天,小朋友们会得到好多糖果。在MAX城市,人民发明了一种糖果自动管理系统(ACM系统),该系统能管理N堆糖果。系统只能执行两种操作。
(1)I a b c(1≤a≤b≤N,0 < c≤100),ACM将在堆a至堆b之间(包含a和b)每堆糖果加c个。
(2)C a b(1≤a≤b≤N),ACM将会选择a到b堆之间糖果数最多的那堆糖果送给一个小朋友。如果有两堆或两堆以上糖果数为最大值,选择那么编号小的那堆。
给出一系列的操作,对于每个C操作,输出堆的糖果数。
【输入】
有多组测试数据。
每组测试数据的第一行为两个整数N,M(0< N,M≤10^5),N表示糖果堆的数目,M表示操作的次数。
下来M行,每行为一个操作。
输入当N=0并且M=0时结束,并且不做任何处理。
初始时,所有堆糖果数目为0。
【输出】
对于每个C操作,输出小朋友能得到的糖果的数目。
某师兄的代码:
#include
#include
const int N=100005;
int n,m;
struct qq
{
int l,r;
int s1,s2;
int z,z1;//最大的值 最大是哪一个编号
int lazy;
}s[N*2];
int num;
void bt (int l,int r)
{
num++;
int a=num;
s[a].l=l;s[a].r=r;
s[a].s1=s[a].s2=-1;
s[a].z=0;
s[a].z1=l;
s[a].lazy=0;
if (l==r) return ;
int mid=(l+r)/2;
s[a].s1=num+1;bt(l,mid);
s[a].s2=num+1;bt(mid+1,r);
return ;
}
void add (int now,int l,int r,int c)
{
//printf("%d %d z:%d lazy:%d\n",s[now].l,s[now].r,s[now].z,s[now].lazy);
if (s[now].l==s[now].r)
{
// printf("YES:%d %d\n",l,r);
s[now].z+=c;
return ;
}
if (s[now].l==l&&s[now].r==r)
{
s[now].lazy+=c;
s[now].z+=c;
return ;
}
int s1=s[now].s1,s2=s[now].s2;
s[s1].lazy+=s[now].lazy;
s[s1].z+=s[now].lazy;
s[s2].lazy+=s[now].lazy;
s[s2].z+=s[now].lazy;
s[now].lazy=0;
int mid=(s[now].l+s[now].r)/2;
if (r<=mid) add(s1,l,r,c);
else if (l>mid) add(s2,l,r,c);
else
{
add(s1,l,mid,c);
add(s2,mid+1,r,c);
}
if (s[s1].z>=s[s2].z)
{
s[now].z=s[s1].z;
s[now].z1=s[s1].z1;
}
else
{
s[now].z=s[s2].z;
s[now].z1=s[s2].z1;
}
return ;
}
int z,z1;
void find (int now,int l,int r)
{
if (s[now].l==l&&s[now].r==r)
{
z=s[now].z;
z1=s[now].z1;
return ;
}
int s1=s[now].s1,s2=s[now].s2;
s[s1].lazy+=s[now].lazy;
s[s1].z+=s[now].lazy;
s[s2].lazy+=s[now].lazy;
s[s2].z+=s[now].lazy;
s[now].lazy=0;
int mid=(s[now].l+s[now].r)/2;
if (r<=mid) find (s1,l,r);
else if (l>mid) find (s2,l,r);
else
{
find(s1,l,mid);
int a=z,a1=z1;
find(s2,mid+1,r);
if (a>=z)
{
z=a;
z1=a1;
}
}
return ;
}
int main()
{
freopen("happy.in","r",stdin);
freopen("happy.out","w",stdout);
while (scanf("%d%d",&n,&m))
{
if (n==0&&m==0) break;
num=0;bt(1,n);
for (int u=1;u<=m;u++)
{
//for (int u=1;u<=num;u++) printf("%d %d %d %d z:%d z1:%d lazy:%d\n",s[u].l,s[u].r,s[u].s1,s[u].s2,s[u].z,s[u].z1,s[u].lazy);
char ss[5];
scanf("%s",ss);
if (ss[0]=='I')
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(1,a,b,c);
}
else
{
int a,b;
scanf("%d%d",&a,&b);
find (1,a,b);
printf("%d\n",z);
/*for (int u=1;u<=num;u++) printf("%d %d %d %d z:%d z1:%d lazy:%d\n",s[u].l,s[u].r,s[u].s1,s[u].s2,s[u].z,s[u].z1,s[u].lazy);
printf("\n");*/
add(1,z1,z1,-z);
}
}
}
return 0;
}