堆
priority_queue
- 包含#include< queue >
- 默认大根堆
q.top();
q.pop();
q.push();
q.size();
codevs 1052地鼠游戏
题目描述 Description
地鼠游戏是一项需要反应速度和敏捷判断力的游戏。游戏开始时,会在地板上一下子冒出很多地鼠来,然后等你用榔头去敲击这些地鼠,每个地鼠被敲击后,将会增加相应的游戏分值。问题是这些地鼠不会傻傻地等你去敲击,它总会在冒出一会时间后又钻到地板下面去(而且再也不上来),每个地鼠冒出后停留的时间可能是不同的,而且每个地鼠被敲击后增加的游戏分值也可能是不同,为了胜出,游戏参与者就必须根据每个地鼠的特性,有选择地尽快敲击一些地鼠,使得总的得分最大。
这个极具挑战性的游戏王钢特别喜欢,最近他经常在星期天上午玩这个游戏,慢慢地他不但敲击速度越来越快(敲击每个地鼠所需要的耗时是1秒),而且他还发现了游戏的一些特征,那就是每次游戏重新开始后,某个地鼠冒出来后停留的时间都是固定的,而且他记录了每个地鼠被敲击后将会增加的分值。于是,他在每次游戏开始后总能有次序地选择敲击不同的地鼠,保证每次得到最大的总分值。
输入描述 Input Description
输入包含3行,第一行包含一个整数n(1<=n<=100)表示有n个地鼠从地上冒出来,第二行n个用空格分隔的整数表示每个地鼠冒出后停留的时间,第三行n个用空格分隔的整数表示每个地鼠被敲击后会增加的分值(<=100)。每行中第i个数都表示第i个地鼠的信息。
输出描述 Output Description
输出只有一行一个整数,表示王钢所能获得的最大游戏总分值。
样例输入 Sample Input
5
5 3 6 1 4
7 9 2 1 5
样例输出 Sample Output
24
solution
- 我们先按松鼠的时间排序,我们发现一个松鼠要不然可以打,要不然一定小于现在的时间1个单位(因为一只松鼠需要1个单位时间)
- 所以贪心,策略为能打就打,不能打只要找到前面松鼠中分值最小的一个(一个就行)和它交换
- 用priority_queue维护最小值
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
inline int read(){
char ch=' ';int f=1;int x=0;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
struct node
{
int t,v;
}a[110];
bool cmp(node a,node b)
{
return a.t<b.t;
}
priority_queue <int> q;
int main()
{
int n=read();
int ti=0,ans=0;
for(int i=1;i<=n;i++) a[i].t=read();
for(int i=1;i<=n;i++) a[i].v=read();
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
if(a[i].t>ti)
{
ti++;
q.push(-a[i].v);
ans+=a[i].v;
}
else
{
int tmp=q.top();tmp=-tmp;
if(tmp>a[i].v) continue;
else
{
ans=ans-tmp+a[i].v;
q.pop();q.push(-a[i].v);
}
}
}
cout<<ans<<endl;
return 0;
}
线段树
1.poj 2777
思路
- 考虑颜色<=30,把颜色压成数位来表示这个节点的状态
- 然后就是区间覆盖
- 唯一改的就是update的或
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=100010;
int s[N<<2];
int tag[N<<2];
inline void update(int rt)
{
s[rt]=s[rt<<1]|s[rt<<1|1];
}
void build(int rt,int l,int r)
{
if(l==r)
{
s[rt]=1;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
update(rt);
}
void pushdown(int rt,int l,int r)
{
if(tag[rt])
{
tag[rt<<1]=tag[rt];
s[rt<<1]=tag[rt];
tag[rt<<1|1]=tag[rt];
s[rt<<1|1]=tag[rt];
tag[rt]=0;
}
}
void modify(int rt,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
s[rt]=1<<(k-1);
tag[rt]=1<<(k-1);
return ;
}
pushdown(rt,l,r);
int mid=(l+r)>>1;
if(x<=mid) modify(rt<<1,l,mid,x,y,k);
if(y>mid) modify(rt<<1|1,mid+1,r,x,y,k);
update(rt);
}
int query(int rt,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
{
return s[rt];
}
pushdown(rt,l,r);
int mid=(l+r)>>1,ret=0;
if(x<=mid) ret=ret|query(rt<<1,l,mid,x,y);
if(y>mid) ret=ret|query(rt<<1|1,mid+1,r,x,y);
return ret;
}
int main()
{
int n,t,m;
scanf("%d%d%d",&n,&t,&m);
char s[10];int a,b,c;
build(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>s;
if(s[0]=='C')
{
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
modify(1,1,n,a,b,c);
}
else
{
scanf("%d%d",&a,&b);
if(a>b) swap(a,b);
int k=query(1,1,n,a,b),ans=0;
while(k)
{
if(k&1==1) ans++;
k=k>>1;
}
cout<<ans<<endl;
}
}
return 0;
}
2HDU2795
思路
- 把每一行当作剩余的空间(列数)当作一个子节点及其权值
- 维护区间最大值
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200010;
int s[N<<2];
int z[N];
inline void update(int rt)
{
s[rt]=max(s[rt<<1],s[rt<<1|1]);
}
void build(int rt,int l,int r,int c)
{
if(l==r)
{
s[rt]=c;
return ;
}
int mid = (l+r) >> 1;
build(rt<<1,l,mid,c);
build(rt<<1|1,mid+1,r,c);
update(rt);
}
int tmp;
void modify(int rt,int l,int r,int c)
{
if(l==r)
{
s[rt]=s[rt]-c;
tmp=l;
return ;
}
int mid= (l+r) >>1;
if(s[rt<<1]>=c)
{
modify(rt<<1,l,mid,c);
}
else
{
modify(rt<<1|1,mid+1,r,c);
}
update(rt);
}
int main()
{
int h,w,n;
int i,j;
while(scanf("%d%d%d",&h,&w,&n)!=EOF)
{
if(h>n)
{
h=n;
}
build(1,1,h,w);
for(i=1;i<=n;i++)
{
scanf("%d",&z[i]);
if(s[1]<z[i])
{
cout<<-1<<endl;
}
else
{
modify(1,1,h,z[i]);
cout<<tmp<<endl;
}
}
}
return 0;
}
3 hdu 1542
扫描线+线段树+离散化
4 hdu 1823
二维线段树
树状数组
ST表
并查集
- 不路径压缩
int find(int x)
{ if(f[x]==x) return x;
return find(f[x]);
}
- 路径压缩
int find(int x)
{
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
虽然改动很小,但是时间复杂度大幅降低
- 按秩合并(小树合到大树上)
void merge(int x,int y)
{
int f1=find(x);
int f2=find(y);
if(siz[f1]>siz[f2])
f[f2]=f1,siz[f1]+=siz[f2];
else f[f1]=f2,siz[f2]+=siz[f1];
}
时间复杂度:路径压缩快于按秩合并,但是按秩合并可以保留树的形态
POJ2492
思路:在一颗并查集内黑白染色
#include <iostream>
#include <cstdio>
using namespace std;
int n,m,fa[100100],dis[100100];
int find(int x)
{
if (fa[x] == x) return x;
find(fa[x]);
dis[x] = dis[x] ^ dis[fa[x]]; fa[x] = fa[fa[x]];
return fa[x];
}
int main()
{
int T = 0;
cin >> T;
for (int t = 1;t <= T;t++)
{
printf("Scenario #%d:\n",t);
cin >> n >> m;
for (int i = 1;i <= n;i++) fa[i] = i,dis[i] = 0;
int x,y; bool yes = 0;
for (int i = 1;i <= m;i++)
{
scanf("%d %d",&x,&y);
int r1 = find(x),r2 = find(y);
int v = dis[x] ^ dis[y];
if (r1 == r2 && v == 0 && yes == 0) {printf("Suspicious bugs found!\n");yes = 1;}
if (r1 != r2) {
fa[r1] = r2; dis[r1] = dis[x] ^ dis[y] ^ 1;
}
}
if (yes == 0) printf("No suspicious bugs found!\n");
printf("\n");
}
}
extra
& P2024
单调栈
#include<stack>
stack <int> s
stack.pop().top().psuh().empty().size()
hdu1506
- 维护左右 最小值
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<stack>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
inline int read(){
char ch=' ';int f=1;int x=0;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
stack <int> s;
const int N=1e5+100;
int a[N],l[N],r[N];
int main()
{
int n;
while(true)
{
n=read();
if(n==0) break;
while(!s.empty()) s.pop();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)
{
while(!s.empty()&&a[i]<=a[s.top()]) s.pop();
if(s.empty()) l[i]=0;
else l[i]=s.top();
s.push(i);
}
while(!s.empty()) s.pop();
for(int i=n;i>=1;i--)
{
while(!s.empty()&&a[i]<=a[s.top()]) s.pop();
if(s.empty()) r[i]=n+1;
else r[i]=s.top();
s.push(i);
}
long long ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,(long long)a[i]*(r[i]-l[i]-1));
printf("%lld\n",ans);
}
return 0;
}
单调队列
这是维护最小值的一个单调队列
- 与普通队列不同的是,单调队列头和尾都可以进出元素
int head,tail;
struct node{ int w,p; }q[N];
int a[N];
void add(int w,int p)
{
while(head<=tail&&w<=q[tail].w) tail--;
tail++;q[tail].p=p;q[tail].w=w;
}
void del(int p)
{
if(q[head].p==p) head++;
}