3264 Balanced Lineup
http://poj.org/problem?id=3264
线段树求区间最值裸题,值得注意的是求最大最小没必要两次去求,因为对于一个确定的区间,无论是求最大值,最小值,区间和,区间平方和还是其他随便什么东西,最终访问到的节点永远是确定的那几个。所以可以用一个全局变量保存所要的答案,然后递归求解就可以了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
int n,q,tmp,a,b;
void read(int &x)
{
x=0;int f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=f;return;
}
int maxans,minans;
#define ADD(x,p) T.add(0,W,RT,(x),(p))
#define QUERY(l,r) T.query(0,W,RT,(l),(r))
const int W=1000005;
int RT=0;
struct Tree{
#define lson l,mid,lp[p]
#define rson mid+1,r,rp[p]
static const int N=W;
int lp[N],rp[N],maxx[N],minn[N];
int tot;
void add(int l,int r,int&p,int a,int x){
if(!p) p=++tot;
if(!maxx[p])maxx[p]=minn[p]=a;
else maxx[p]=max(maxx[p],a),minn[p]=min(minn[p],a);
if(l==r) return;
int mid=l+r>>1;
if(x>mid) add(rson,a,x);
else add(lson,a,x);
}
void query(int l,int r,int p,int a,int b){
if(l==a and r==b) {
maxans=max(maxx[p],maxans);
minans=min(minn[p],minans);
return;
}
int mid=l+r>>1;
if(a>mid) query(rson,a,b);
else if(b<=mid) query(lson,a,b);
else{
query(lson,a,mid);
query(rson,mid+1,b);
}
return;
}
}T;
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
read(tmp);
ADD(tmp,i);
}
for(int i=0;i<q;i++){
maxans=-1;
minans=1e9+7;
read(a);
read(b);
QUERY(a,b);
cout<<maxans-minans<<endl;
}
}
1860 Currency Exchange
http://poj.org/problem?id=1860
题意是给你一些货币间的汇率和抽成,问你能否在一系列操作之后赚到钱。因为每两种货币之间的兑换是双向的,也就是说,如果在图中存在一个正权回路,那么在绕它足够多次后回到出发点必定能赚钱。所以问题就转化为找正权回路的问题,所以就开开心心打了一个spfa。
struct edge{int to,next;double com,ratio;}e[20005];
int tail[105],cnt=0;
void add_edge(int from,int to,double ratio,double com){
e[++cnt].to=to;
e[cnt].next=tail[from];
e[cnt].ratio=ratio;
e[cnt].com=com;
tail[from]=cnt;
}
int q[10005],vis[105],inq[105];
int hi=0,lo=0;
double w[105];
int n,m,s,a,b;
double v,r1,c1,r2,c2;
bool spfa(){
while(lo<=hi){
int cur=q[lo++];
vis[cur]=0;
++inq[cur];
if(inq[cur]>n)return 1;
for(int i=tail[cur];i;i=e[i].next){
int nx=e[i].to;
double tmp=(w[cur]-e[i].com)*e[i].ratio;
if(tmp>w[nx]){
if(!vis[nx]){
q[++hi]=nx;
vis[nx]=1;
}
w[nx]=tmp;
}
}
}
return 0;
}
int main()
{
cin>>n>>m>>s>>v;
w[s]=v;
for(int i=0;i<m;i++){
cin>>a>>b>>r1>>c1>>r2>>c2;
add_edge(a,b,r1,c1);
add_edge(b,a,r2,c2);
}
q[0]=s;
if(spfa())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
3259 Wormholes
http://poj.org/problem?id=3259
这题和上题差不多,就是一个找负环的题,spfa搞定。但是可能因为写代码的时候注意力不集中,所以出现了巨量多的bug,并且垃圾dev还不给我报错,太难过了。记录一下防止忘记:
1.从1~n赋初值再读入n(是不是因为最近帮同学调代码而看到了太多这样的奇怪操作???)
2.队列开太小了,少打一位(500*500==250000)
3.变量名重复定义(以后定义变量尽量定义在一起,要么全部全局,要么全放函数了,临时变量除外)
调bug使人憔悴orz
struct edge{
edge(){}
edge(int a,int b,int c):to(a),next(b),w(c){}
int to,next,w;
}e[10005];
int tail[505],cnt=0;
void add_edge(int from,int to,int w){
e[++cnt]=edge(to,tail[from],w);
tail[from]=cnt;
}
int n,m,w,F,T,V;
int dis[505],inq[505],vis[505];
int q[300005],hi,lo;
bool spfa(){
while(lo<=hi){
int cur=q[lo++];
vis[cur]=0;
if(++inq[cur]>n)return 1;
for(int i=tail[cur];i;i=e[i].next){
int nx=e[i].to;
int del=e[i].w;
if(dis[cur]+del<dis[nx]){
if(!vis[nx]){
++vis[nx];
q[++hi]=nx;
}
dis[nx]=dis[cur]+del;
}
}
}
return 0;
}
int main()
{
int Time;
cin>>Time;
while(Time--){
INI(tail);
INI(inq);
INI(vis);
q[0]=1;
dis[1]=hi=lo=cnt=0;
cin>>n>>m>>w;
for(int i=2;i<=n;++i)dis[i]=1e9+7;
for(int i=0;i<m;++i){
cin>>F>>T>>V;
add_edge(F,T,V);
add_edge(T,F,V);
}
for(int i=0;i<w;++i){
cin>>F>>T>>V;
add_edge(F,T,-V);
}
if(spfa())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}