线段树专辑 —— pku 3145 Harmony Forever
2011-11-14 20:06
369 查看
http://poj.org/problem?id=3145
Harmony Forever。。。多吹牛B啊。
这题巧妙的运用了鸽笼原理,什么是鸽笼原理?鸽笼原理就是给你N+1个数,则必定至少有两个数的余数是相同的!
解决这题的时候,我们先用RMQ的方法求出每一段的最小值,这是容易做到的。
这题的数据范围是500000,也就是说最多会有500000个叶子节点,当该叶子节点的值为inf的时候,表示这里没有值。当它的值等于它的位置的时候,表示它有值,例如:
集合[3,4,5]在线段树中叶子节点中的表示为 [inf,inf,inf,3,4,5],前面三个inf分别表示0位,1位和2位
询问的时候,假设我们要求的MOD是Y,则首先查找[0,Y-1]区间的最小值,因为这样的区间不会有两个数的余数相同,记录下结果。然后依次查找[Y,Y+Y-1],[Y+Y,Y+Y+Y-1]。。。。等区间,每个区间都会找出一个最小值,我们将这些最小值对Y进行取模,得到最小值!
还是看上面的例子,假如现在MOD是4.
根据上面的方法,我们便先查找[0,3],得到最小值是3,3%4==3,这是目前的答案。
接下来查找区间[4,5],得到最小值4,4%4==0,这便是最新的答案!
从这个例子中,我们也可以看到鸽笼原理的正确性,不过不对的话,那么假如我们首先查找区间[0,4],那么最小值是3,再查找区间[5,5],最小值是5,这样的话,最优的4就被我们丢了!
关于鸽笼原理更多知识,看组合数学吧!
View Code
Harmony Forever。。。多吹牛B啊。
这题巧妙的运用了鸽笼原理,什么是鸽笼原理?鸽笼原理就是给你N+1个数,则必定至少有两个数的余数是相同的!
解决这题的时候,我们先用RMQ的方法求出每一段的最小值,这是容易做到的。
这题的数据范围是500000,也就是说最多会有500000个叶子节点,当该叶子节点的值为inf的时候,表示这里没有值。当它的值等于它的位置的时候,表示它有值,例如:
集合[3,4,5]在线段树中叶子节点中的表示为 [inf,inf,inf,3,4,5],前面三个inf分别表示0位,1位和2位
询问的时候,假设我们要求的MOD是Y,则首先查找[0,Y-1]区间的最小值,因为这样的区间不会有两个数的余数相同,记录下结果。然后依次查找[Y,Y+Y-1],[Y+Y,Y+Y+Y-1]。。。。等区间,每个区间都会找出一个最小值,我们将这些最小值对Y进行取模,得到最小值!
还是看上面的例子,假如现在MOD是4.
根据上面的方法,我们便先查找[0,3],得到最小值是3,3%4==3,这是目前的答案。
接下来查找区间[4,5],得到最小值4,4%4==0,这便是最新的答案!
从这个例子中,我们也可以看到鸽笼原理的正确性,不过不对的话,那么假如我们首先查找区间[0,4],那么最小值是3,再查找区间[5,5],最小值是5,这样的话,最优的4就被我们丢了!
关于鸽笼原理更多知识,看组合数学吧!
View Code
#include<iostream> #include<string> #include<cmath> #include<algorithm> using namespace std; #define inf 500005 struct node { int l; int r; int min_val; }; node tree[2500000]; int n,len; int pos[inf]; int val[inf]; int min(int a,int b) { return a<b?a:b; } void build(int i,int l,int r) { tree[i].l=l; tree[i].r=r; tree[i].min_val=inf; if(l==r) return; int mid=(l+r)/2; build(2*i,l,mid); build(2*i+1,mid+1,r); } void updata(int i,int w) //更新区间[l,r] { if(tree[i].l>w || tree[i].r<w) return; if(tree[i].l>=w && tree[i].r<=w) { tree[i].min_val=w; return; } updata(2*i,w); updata(2*i+1,w); tree[i].min_val=min(tree[2*i].min_val,tree[2*i+1].min_val); } int find(int i,int l,int r) //返回区间[l,r]的最小值 { if(tree[i].l>r || tree[i].r<l) return inf; if(tree[i].l>=l && tree[i].r<=r) return tree[i].min_val; if(tree[i].l<tree[i].r) { return min(find(2*i,l,r),find(2*i+1,l,r)); } return inf; } int fun(int y) //直接查找 { int i,ans=inf,k; for(i=len;i>=1;i--) { if(val[i]%y==0) { return i; } if(val[i]%y<ans) { ans=val[i]%y; k=i; } } return k; } int solve(int mod) { int l=0,r=mod-1,ans=inf,k,temp;//[l,r]便是鸽笼的大小 while(l<=500000) { if(r>500000) r=500000; temp=find(1,l,r); if(temp!=inf && temp%mod<ans) { ans=temp%mod; k=pos[temp]; } else if(temp%mod==ans && pos[temp]>k) { k=pos[temp]; } l+=mod; r+=mod; } return k; } int main() { char c; int x,cas=1,i,ans; //freopen("d:\\in.txt","r",stdin); while(scanf("%d",&n)!=EOF && n) { if(cas>1) printf("\n"); build(1,0,500000); printf("Case %d:\n",cas++); len=0; for(i=0;i<n;i++) { getchar(); scanf("%c %d",&c,&x); if(c=='B') { len++; pos[x]=len; val[len]=x; updata(1,x); } else { if(len==0) { printf("-1\n"); continue; } if(x<=5000)//范围较小的时候直接查找 { ans=fun(x); printf("%d\n",ans); } else { ans=solve(x); printf("%d\n",ans); } } } } return 0; }
相关文章推荐
- 线段树专辑—— pku 1436 Horizontally Visible Segments
- 线段树专辑——pku 2528 Mayor's posters
- 线段树专辑 —— pku 3225 Help with Intervals
- 线段树专辑 —— pku 2482 Stars in Your Window
- 线段树专辑 —— pku 2828 Buy Tickets
- 线段树专辑——pku 2886 Who Gets the Most Candies?
- 线段树专辑——pku 3667 Hotel
- POJ-3145-Harmony Forever-线段树暴力
- poj 3145 Harmony Forever(线段树)
- 线段树专辑——pku 2777 Count Color
- 线段树专辑—— pku 3468 A Simple Problem with Integers
- 线段树专辑(转)
- hdu 1542 poj/pku 1151(线段树求面积并)
- 【线段树】PKU2777 区间更新区间询问(位优化)
- 线段树专辑(转)
- hdu 3303 Harmony Forever (线段树 + 抽屉原理)
- pku 3264 Balanced Lineup(线段树)
- pku 2777 cout the color--线段树
- 简单线段树专辑(未完待续 poj3468+hdu1698+hdu4325+hdu1394+poj2777
- pku 暑假培训1 线段树和树状数组