HUT 线段树练习 部分题解
F-poj 2886
这题去年月神给我们14级的抓过。然而比较偏数学。
题意大概是n个小朋友围成一圈,每个小朋友手里都有一张卡片,卡片上有个数字a[i]。
从第k个小朋友开始,第k个小朋友出圈,然后让他的左手方向的第a[k]个小朋友出圈。然后这个小朋友又根据规则让另一个小朋友出圈。
第p个出圈的小朋友拿到的糖果数目为p的因子个数,问谁拿到了最多的糖果
如果我们从1到n,逐个判断它的因子数目有多少个,效率非常低。其实我们可以通过规律直接dfs出小于等于n的,因子个数最多的数
因为要使因子个数尽量的多,该数应该满足如下性质,即可以表示为一系列连续质数的积,形如n=2^x1*3^x2*5^x3......
于是我们根据这个思路进行dfs。然后我们就得到是第几个出圈的人拿到最多的糖果啦。
之后我们要用线段树,求得拿到最多糖果的人是谁。
线段树维护区间当前的人数,然后把查询左手方向的第a[k]个小朋友,转化为查询剩余数组的第k的小朋友(取相对位置),就能直接在线段树中查询了
这里有关于反素数比较详细的介绍http://blog.csdn.net/ACdreamers/article/details/25049767
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500008;
int p[16]={2,3,5,7,11,13,17,19,23,29,31,37};
int mx,nx;
void dfs(int num,int x,int y,int lim)
{
if(num>=9) return;
if(mx<x)
{
mx=x;
nx=y;
}
if(mx==x&&nx>y)
nx=y;
int i;
for(i=1;i<=10;i++)
{
if(lim<y*p[num]) break;
y*=p[num];
dfs(num+1,x*(i+1),y,lim);
}
}
struct fuck{
int x;
char s[15];
}f[maxn];
int a[maxn<<2];
void build(int x,int y,int c)
{
if(x==y)
{
a[c]=1;
return;
}
int mid=(x+y)>>1;
build(x,mid,c<<1);
build(mid+1,y,c<<1|1);
a[c]=a[c<<1]+a[c<<1|1];
}
int update(int m,int x,int y,int c)
{
a[c]--;
if(x==y)
{
return x;
}
int mid=(x+y)>>1;
if(m<=a[c<<1]) return update(m,x,mid,c<<1);
else return update(m-a[c<<1],mid+1,y,c<<1|1);
}
int main()
{
int i,j,n,m;
while(scanf("%d%d",&n,&m)==2)
{
mx=nx=1;
dfs(0,1,1,n);
for(i=1;i<=n;i++)
scanf("%s%d",f[i].s,&f[i].x);
build(1,n,1);
int k=n;
int shit;
for(i=1;i<=nx;i++)
{
k--;
shit=update(m,1,n,1);
if(k<=0) break;
if(f[shit].x>0)
m=(m-1+f[shit].x-1)%k+1;
else
m=((m+f[shit].x-1)%k+k)%k+1;
}
printf("%s %d\n",f[shit].s,mx);
}
return 0;
}
H - Mayor's posters
找一找可以发现别人转载的杭电老队长博客,里面有这题的详细介绍,关于离散化也有详细的讲解
http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html
I-hdu 1540 Tunnel Warfare
有可以看做一条线的村庄互相用地道连接。敌人会破坏一些村庄。八路军可以修好前一个被破坏的村庄。询问第k个村庄直接或间接连接了多少个村子。
区间合并问题。我的做法直接开两颗线段树。一颗存区间内最左边的,没有被破坏的村庄编号。一颗存区间内最右边的,没有被破坏的村庄编号,查询两次,将其相加即是答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=50008;
const int INF=0x7f7f7f7f;
int a[maxn<<4];
int b[maxn<<4];
int st[maxn];
int n;
void build(int x,int y,int c)
{
if(x==y)
{
a[c]=n+1;
b[c]=0;
return;
}
int mid=(x+y)>>1;
build(x,mid,c<<1);
build(mid+1,y,c<<1|1);
a[c]=min(a[c<<1],a[c<<1|1]);
b[c]=max(b[c<<1],b[c<<1|1]);
}
void update(int sx,int sy,int x,int y,int c)
{
if(x==y)
{
if(sy==0)
{
b[c]=a[c]=x;
}
else
{
b[c]=0;a[c]=n+1;
}
return;
}
int mid=(x+y)>>1;
if(sx<=mid) update(sx,sy,x,mid,c<<1);
else update(sx,sy,mid+1,y,c<<1|1);
a[c]=min(a[c<<1],a[c<<1|1]);
b[c]=max(b[c<<1],b[c<<1|1]);
}
int yquery(int sx,int sy,int x,int y,int c)
{
if(sx<=x&&y<=sy)
{
return a[c];
}
int mid=(x+y)>>1;
int ans=n+1;
if(sx<=mid) ans=min(ans,yquery(sx,sy,x,mid,c<<1));
if(sy>mid) ans=min(ans,yquery(sx,sy,mid+1,y,c<<1|1));
return ans;
}
int xquery(int sx,int sy,int x,int y,int c)
{
if(sx<=x&&y<=sy)
{
return b[c];
}
int mid=(x+y)>>1;
int ans=0;
if(sx<=mid) ans=max(ans,xquery(sx,sy,x,mid,c<<1));
if(sy>mid) ans=max(ans,xquery(sx,sy,mid+1,y,c<<1|1));
return ans;
}
bool query(int sx,int x,int y,int c)
{
if(x==y)
{
if(a[c]==x) return true;
return false;
}
int mid=(x+y)>>1;
if(sx<=mid) return query(sx,x,mid,c<<1);
else return query(sx,mid+1,y,c<<1|1);
}
int main()
{
int i,j,m;
char s[5];
while(scanf("%d%d",&n,&m)==2)
{
build(1,n,1);
int u;
int top=0;
while(m--)
{
scanf("%s",s);
if(s[0]=='R')
{
update(st[--top],1,1,n,1);
}
else
{
scanf("%d",&u);
if(s[0]=='D')
{
update(u,0,1,n,1);
st[top++]=u;
}
else
{
int bitch;
if(query(u,1,n,1)) bitch=0;
else
{
bitch=1;
if(u>1)
bitch+=(u-xquery(1,u-1,1,n,1)-1);
if(u<n)
bitch+=(yquery(u+1,n,1,n,1)-u-1);
}
printf("%d\n",bitch);
}
}
}
}
return 0;
}
J-light oj 1120
扫描线问题需要会离散化,区间更新。而且这里的区间更新非常灵活,不是pushdown,而是pushup。根据需要解锁不同姿势。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll __int64
const int maxn=30008;
struct fuck{
int x,y,u,v;
int idx;
int w;
bool operator<(const fuck &a) const
{
return idx<a.idx;
}
}f[maxn<<1];
int tol;
int re;
int a[maxn<<1];
int b[maxn<<1];
ll st[maxn<<4];
int lazy[maxn<<4];
int shit[maxn];
int bs(int x)
{
int left,right;
left=1;right=re;
while(left<=right)
{
int mid=(left+right)>>1;
if(b[mid]<x) left=mid+1;
else right=mid-1;
}
return left;
}
void init()
{
memset(st,0,sizeof(st));
memset(lazy,0,sizeof(lazy));
}
void pushup(int c,int x,int y)
{
if(lazy[c]) st[c]=b[y+1]-b[x];
else if(x==y) st[c]=0;
else st[c]=st[c<<1]+st[c<<1|1];
}
void update(int sx,int sy,int w,int x,int y,int c)
{
if(sx>sy) return;
if(sx<=x&&y<=sy)
{
lazy[c]+=w;
pushup(c,x,y);
return;
}
int mid=(x+y)>>1;
if(sx<=mid) update(sx,sy,w,x,mid,c<<1);
if(sy>mid) update(sx,sy,w,mid+1,y,c<<1|1);
pushup(c,x,y);
return;
}
int main()
{
int i,j,t,n,m,x,y,sx,sy,u,v;
int cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
tol=0;
for(i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x,&y,&sx,&sy);
f[++tol].idx=x;f[tol].x=y;f[tol].y=sy;
a[tol]=y;f[tol].w=1;
f[++tol].idx=sx;f[tol].x=y;f[tol].y=sy;
a[tol]=sy;f[tol].w=-1;
}
sort(f+1,f+tol+1);
sort(a+1,a+tol+1);
// printf("%d\n",tol);
a[0]=-1;re=0;
for(i=1;i<=tol;i++)
if(a[i]!=a[i-1])
b[++re]=a[i];
ll sum=0;
init();
for(i=1;i<=tol;i++)
{
u=bs(f[i].x);
v=bs(f[i].y);
//printf("%d %d\n",u,v);
if(i==1)
update(u,v-1,f[i].w,1,re,1);
else
{
// printf("%d\n",st[1]);
sum+=st[1]*((ll)f[i].idx-(ll)f[i-1].idx);
update(u,v-1,f[i].w,1,re,1);
}
}
printf("Case %d: %lld\n",cas++,sum);
}
return 0;
}
L-uvalive 4730 kingdom
大白薯上的题。抓这题是liji的主意。线段树+并查集。
在二维坐标上有一系列的点,每个点代表一个城市。进行一系列的操作。一种操作是将两个城市相连接,互通的城市形成一个州。另一个操作是询问y直线一共穿过了多少州和城市
用并查集维护州的相连情况,然后分类讨论,更新y轴的城市和州分布情况,又是区间更新加离散化orz。
分类讨论其实很简单。你需要仔细想想,什么情况下点y的州数目和城市数目变化,什么情况不变化,按照思路更新即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define db double
const int maxn=200008;
struct poi{
int x,y;
int idx;
bool operator<(const poi &a) const
{
return y<a.y;
}
}f[maxn];
int g[maxn];
int rel[maxn];
int a[maxn<<4],b[maxn<<4];
int lazya[maxn<<4],lazyb[maxn<<4];
struct fuck{
int next;
int x,y;
int w;
}uni[maxn];
void init(int n)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(lazya,0,sizeof(lazya));
memset(lazyb,0,sizeof(lazyb));
for(int i=1;i<=n;i++)
{
uni[i].next=i;
uni[i].x=uni[i].y=rel[i];
uni[i].w=1;
}
}
int find(int u)
{
if(u==uni[u].next) return u;
return uni[u].next=find(uni[u].next);
}
void pushdowna(int c)
{
if(lazya[c]==0) return;
lazya[c<<1]+=lazya[c];
lazya[c<<1|1]+=lazya[c];
a[c<<1]+=lazya[c];
a[c<<1|1]+=lazya[c];
lazya[c]=0;
}
void pushdownb(int c)
{
if(lazyb[c]==0) return;
lazyb[c<<1]+=lazyb[c];
lazyb[c<<1|1]+=lazyb[c];
b[c<<1]+=lazyb[c];
b[c<<1|1]+=lazyb[c];
lazyb[c]=0;
}
void update(int sx,int sy,int w,int x,int y,int c)
{
if(sx>sy) return;
if(sx<=x&&y<=sy)
{
a[c]+=w;
lazya[c]+=w;
return;
}
pushdowna(c);
int mid=(x+y)>>1;
if(sx<=mid) update(sx,sy,w,x,mid,c<<1);
if(mid<sy) update(sx,sy,w,mid+1,y,c<<1|1);
return;
}
void updateb(int sx,int sy,int w,int x,int y,int c)
{
if(sx>sy) return;
if(sx<=x&&y<=sy)
{
b[c]+=w;
lazyb[c]+=w;
return;
}
pushdownb(c);
int mid=(x+y)>>1;
if(sx<=mid) updateb(sx,sy,w,x,mid,c<<1);
if(mid<sy) updateb(sx,sy,w,mid+1,y,c<<1|1);
return;
}
int bs(db shit,int n)
{
int left,right;
left=1;right=n;
while(left<=right)
{
int mid=(left+right)>>1;
if(f[mid].y<shit) left=mid+1;
else right=mid-1;
}
return left-1;
}
int query(int sx,int x,int y,int c)
{
if(x==y)
{
return a[c];
}
pushdowna(c);
int mid=(x+y)>>1;
if(sx<=mid) return query(sx,x,mid,c<<1);
else return query(sx,mid+1,y,c<<1|1);
}
int queryb(int sx,int x,int y,int c)
{
if(x==y)
{
return b[c];
}
pushdownb(c);
int mid=(x+y)>>1;
if(sx<=mid) return queryb(sx,x,mid,c<<1);
else return queryb(sx,mid+1,y,c<<1|1);
}
int main()
{
int i,j,t,n,m,u,v,x,y;
scanf("%d",&t);
char s[10];
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&f[i].x,&f[i].y);
f[i].idx=i;
}
sort(f+1,f+1+n);
for(i=1;i<=n;i++)
g[f[i].idx]=i;
int pre=-1,k=0;
for(i=1;i<=n;i++)
{
if(f[i].y!=pre)
rel[i]=++k;
else
rel[i]=k;
pre=f[i].y;
}
init(n);
scanf("%d",&m);
while(m--)
{
scanf("%s",s);
if(s[0]=='r')
{
scanf("%d%d",&u,&v);
u++;v++;
u=g[u];v=g[v];
x=find(u);y=find(v);
if(x!=y)
{
if(uni[x].y>uni[y].y){
int shit=x;x=y;y=shit;
}
if(uni[x].y<uni[y].x)
{
update(uni[x].y,uni[y].x-1,1,1,k,1);
updateb(uni[x].y,uni[y].x-1,uni[y].w+uni[x].w
,1,k,1);
updateb(uni[x].x,uni[x].y-1,uni[y].w,1,k,1);
updateb(uni[y].x,uni[y].y-1,uni[x].w,1,k,1);
}
else
{
update(max(uni[y].x,uni[x].x),
uni[x].y-1,-1,1,k,1);
updateb(uni[x].x,uni[y].x-1,uni[y].w,1,k,1);
updateb(uni[y].x,uni[x].x-1,uni[x].w,1,k,1);
updateb(uni[x].y,uni[y].y-1,uni[x].w,1,k,1);
}
uni[x].next=y;
uni[y].w+=uni[x].w;
uni[y].x=min(uni[x].x,uni[y].x);
}
}
else
{
db shit;
scanf("%lf",&shit);
if(shit<f[1].y)
{
printf("0 0\n");
continue;
}
x=bs(shit,n);
x=rel[x];
int sx=query(x,1,k,1);
int sy=queryb(x,1,k,1);
printf("%d %d\n",sx,sy);
}
}
}
return 0;
}
浙公网安备 33010602011771号