您的位置:首页 > 其它

省选专练[SCOI2013]摩托车交易[NOIP2013]货车运输

2018-02-27 20:44 501 查看
经典题。
做一次MST
然后跑LCA
这样的题我做了五个:



交易啊!交易啊!
跑一个最大生成树,然后贪心就好了
来源:某7th sc
代码丑陋。#include<bits/stdc++.h>
using namespace std;
#define LL "%lld
const int BUF_SIZE = 30;
char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;

#define PTR_NEXT() \
{ \
buf_s ++; \
if (buf_s == buf_t) \
{ \
buf_s = buf; \
buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); \
} \
}

#define readint(_n_) \
{ \
while (*buf_s != '-' && !isdigit(*buf_s)) \
PTR_NEXT(); \
bool register _nega_ = false; \
if (*buf_s == '-') \
{ \
_nega_ = true; \
PTR_NEXT(); \
} \
int register _x_ = 0; \
while (isdigit(*buf_s)) \
{ \
_x_ = _x_ * 10 + *buf_s - '0'; \
PTR_NEXT(); \
} \
if (_nega_) \
_x_ = -_x_; \
(_n_) = (_x_); \
}

const int maxn=300010;
const int maxm=300010;
const long long INF=0x3f3f3f3f3f3f3f3fll;

int n,m,Q,en,value[maxn],order[maxn],s[maxm],e[maxm],z[maxm],f[maxn][20],depth[maxn],q[maxn],fa[maxn],train[maxn];

long long limit[maxn][20],w[maxm];

struct edge
{
int e;
long long d;
edge *next;
}*v[maxn],ed[maxn<<1];

void add_edge(int s,int e,long long d)
{
en++;
ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
}

int getf(int now)
{
if (fa[now]==now) return now;
else return fa[now]=getf(fa[now]);
}

bool cmp(int a,int b)
{
return w[a]>w[b];
}

void bfs(int rt)
{
depth[rt]=1;
int front=1,tail=1;
q[1]=rt;
for (;front<=tail;)
{
int now=q[front++];
for (edge *e=v[now];e;e=e->next)
if (!depth[e->e])
{
depth[e->e]=depth[now]+1;
f[e->e][0]=now;
limit[e->e][0]=e->d;
int nowp=now,x=0;
while (f[nowp][x])
{
f[e->e][x+1]=f[nowp][x];
limit[e->e][x+1]=min(limit[e->e][x],limit[nowp][x]);
nowp=f[nowp][x];
x++;
}
q[++tail]=e->e;
}
}
}

long long solve(int p1,int p2)
{
long long ans=INF;
if (depth[p1]<depth[p2]) swap(p1,p2);
int delta=depth[p1]-depth[p2],x=0;
while (delta)
{
if (delta&1)
{
ans=min(ans,limit[p1][x]);
p1=f[p1][x];
}
delta>>=1;
x++;
}
x=0;
while (p1!=p2)
{
if (!x || f[p1][x]!=f[p2][x])
{
ans=min(ans,min(limit[p1][x],limit[p2][x]));
p1=f[p1][x];
p2=f[p2][x];
x++;
}
else x--;
}
return ans;
}

int main()
{

readint(n);
readint(m);
readint(Q);
for (int a=1;a<=n;a++)
{
readint(order[a]);
}
for (int a=1;a<=n;a++)
{
readint(value[a]);
}
for (int a=1;a<=m;a++)
{
readint(s[a]);
readint(e[a]);
readint(w[a]);
}
for (int a=1;a<=Q;a++)
{
readint(train[a]);
}
for (int a=2;a<=Q;a++)
{
s[++m]=train[a-1];
e[m]=train[a];
w[m]=INF;
}
for (int a=1;a<=m;a++)
z[a]=a;
sort(z+1,z+m+1,cmp);
for (int a=1;a<=n;a++)
fa[a]=a;
for (int a=1;a<=m;a++)
{
int now=z[a];
if (getf(s[now])!=getf(e[now]))
{
fa[getf(s[now])]=getf(e[now]);
add_edge(s[now],e[now],w[now]);
add_edge(e[now],s[now],w[now]);
}
}
bfs(1);
int nowp=order[1];
long long nowgold;
if (value[nowp]<0) printf("0\n"),nowgold=0;
else nowgold=value[nowp];
for (int a=2;a<=n;a++)
{
nowgold=min(nowgold,solve(order[a-1],order[a]));
nowp=order[a];
if (value[nowp]>0) nowgold+=value[nowp];
else
{
long long delta=min(nowgold,-(long long)value[nowp]);
nowgold-=delta;
printf("%lld\n",delta);
}
}

return 0;
}



简单啊!简单啊!
跑一个最大生成树就完了LCA查
这个算法有bug,一条链就卡死了#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
inline 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;
}
struct Front_star{
int u,v,w,nxt;
}e[200010],edge[200010];
int cnt=0;
int first[100010]={0};
void add(int u,int v,int w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
}
int edgecnt=0;
void addedge(int u,int v,int w){
edgecnt++;
edge[edgecnt].u=u;
edge[edgecnt].v=v;
edge[edgecnt].w=w;
edge[edgecnt].nxt=first[u];
first[u]=edgecnt;
}
int n,m,q;
//kruskal
int fa[100010]={0};
int getfa(int x){
if(fa[x]==x)
return x;
return fa[x]=getfa(fa[x]);
}
bool cmp(Front_star a,Front_star b){
return a.w<b.w;
}
void kruskal(){
sort(e+1,e+1+cnt,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=cnt;i++){
int x=getfa(e[i].u);
int y=getfa(e[i].v);
if(x!=y){
fa[x]=y;
addedge(e[i].u,e[i].v,e[i].w);
addedge(e[i].v,e[i].u,e[i].w);
}
}
}
// LCA
int vis[100010]={0};
int dep[100010]={0};
int p[200010][30]={0};
int dis[100010]={0};
void dfs(int u){
vis[u]=1;
for(int i=first[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(!vis[v]){
dep[v]=dep[u]+1;
p[v][0]=u;
dis[v]=edge[i].w;
dfs(v);
}
}
}
void init(){
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++){
p[i][j]=p[p[i][j-1]][j-1];
}
}
}
int LCA(int x,int y){
if(dep[x]<dep[y])
swap(x,y);
int i;
for(i=0;(1<<i)<=dep[x];i++);
i--;
for(int j=i;j>=0;j--){
if(dep[x]-(1<<j)>=dep[y])
x=p[x][j];
}
if(x==y)
return x;
for(int j=i;j>=0;j--){
if(p[x][j]!=p[y][j]){
x=p[x][j];
y=p[y][j];
}
}
return p[x][0];
}
int getans(int x,int y){
int sum=LCA(x,y);
int a=-1;
int b=-1;
for(int i=x;i!=sum;i=p[i][0])
a=max(a,dis[i]);
for(int i=y;i!=sum;i=p[i][0])
b=max(b,dis[i]);
return max(a,b);
}
int main(){
read(n);
read(m);
for(int i=1;i<=m;i++){
int u,v,w;
read(u);
read(v);
read(w);
add(u,v,w);
add(v,u,w);
}
kruskal();
dep[1]=1;
p[1][0]=0;
dfs(1);
init();
read(q);
for(int i=1;i<=q;i++){
int x,y;
read(x);
read(y);
int ans=getans(x,y);
printf("%d\n",ans);
}
}



货车运输:难住不少人的NOIP题。
貌似和简单题完全一个做法。
万恶之源。就是这里我发现bfs丑陋。
然后写了个错误的dfs#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int fa[20000]={0};//kruskalµÄ²¢²é¼¯£¬²¢ÓÃÀ´ÅжÏ-1
struct Node{
int u,v,w;
}e[100000];
struct Front_star{
int u,v,w,nxt;
}edge[100000];
int cnt=0;
int first[20000]={0};
void addedge(int u,int v,int w){
cnt++;
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=first[u];
first[u]=cnt;
}
int n,m,q;
int tot=0;
void add(int u,int v,int w){
tot++;
e[tot].u=u;
e[tot].v=v;
e[tot].w=w;
}
//----------×î´óÉú³ÉÊ÷
int getfa(int x){
if(fa[x]==x){
return x;
}
return fa[x]=getfa(fa[x]);
}
void merge(int x,int y){
int a=getfa(x);
int b=getfa(y);
fa[b]=a;
}
bool cmp(Node a,Node b){
return a.w>b.w;
}
void kruskal(){
for(int i=1;i<=n;i++)
fa[i]=i;
sort(e+1,e+1+tot,cmp);
for(int i=1;i<=tot;i++){
int fx=getfa(e[i].u);
int fy=getfa(e[i].v);
if(fx==fy)
continue;
addedge(fa[fx],fy,e[i].w);
fa[fy]=fx;
}
}
//LCA
int ST[20000][20]={0};
int dep[20000]={0};
int dis[20000]={0};
void dfs(int u){
for(int j=1;j<=14;j++){
ST[u][j]=ST[ST[u][j-1]][j-1];
}
for(int i=first[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(ST[u][0]==v)
continue;
ST[v][0]=u;
dis[v]=edge[i].w;
dep[v]=dep[u]+1;
dfs(v);
}
}
int LCA(int x,int y){
int i,j;
if(dep[x]<dep[y]){
swap(x,y);
}
int h=dep[x]-dep[y];
// for(i=1;(1<<i)<=dep[x];i++);
// i--;
for(j=14;j>=0;j--){
if(h&(1<<j))
x=ST[x][j];
}
if(x==y){
return x;
}
if(x!=y){
for(j=14;j>=0;j--){
if(ST[x][j]!=ST[y][j]){
x=ST[x][j];
y=ST[y][j];
}
}
x=ST[x][0];
}
return x;
}
int getans(int x,int y){
int a=0x7fffffff;
int b=0x7fffffff;
int sum=LCA(x,y);
// cout<<sum<<endl;
for(int i=x;i!=sum;i=ST[i][0]){
a=min(a,dis[i]);
}
for(int i=y;i!=sum;i=ST[i][0]){
b=min(b,dis[i]);
}
return min(a,b);
}
int main(){
scanf("%d",&n);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int u;
int v;
int w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
kruskal();
for(int i=1;i<=n;i++){
i
4000
f(getfa(i)==i){
ST[i][0]=i;
dfs(i);
}
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
int x,y;
scanf("%d%d",&x,&y);
if(getfa(x)!=getfa(y)){
printf("-1\n");
}
else{
int ans=getans(x,y);
printf("%d\n",ans);
}
}
}



稍微难一些。
他这个有球员名字。
不只是编号。
所以可以哈希STL。
map查重
这个时候我发现:为什么莫名超时?
发现跳链很SB。#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define N 200000
using namespace std;
inline void read(int &sum){
char ch=getchar(); sum=0;
while(!(ch>='0'&&ch<='9'))ch=getchar();
while(ch>='0'&&ch<='9')sum=(sum<<1)+(sum<<3)+ch-48,ch=getchar();
}
map<string,int> name;
int n,m;
int first
={0};
int name_cnt=0;
int cnt=0;// e's
int tot=0;// edge's
struct Front_star{
int u,v,w,nxt;
}edge[2*N];
struct Node{
int u,v,w;
}e[2*N];
int fa
={0};
void add(int u,int v,int w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
}
void addedge(int u,int v,int w){
tot++;
edge[tot].u=u;
edge[tot].v=v;
edge[tot].w=w;
edge[tot].nxt=first[u];
first[u]=tot;
}
//--------------
bool cmp(Node a,Node b){
return a.w<b.w;
}
int getfa(int x){
if(fa[x]==x)
return x;
return fa[x]=getfa(fa[x]);
}
void kruskal(){
for(int i=1;i<=n;i++)
fa[i]=i;
sort(e+1,e+1+cnt,cmp);
for(int i=1;i<=cnt;i++){
int fx=getfa(e[i].u);
int fy=getfa(e[i].v);
if(fx==fy)
continue;
fa[fy]=fx;
addedge(fa[fx],fy,e[i].w);
}
}
//-------------
int p
[30]={0};
int dep
={0};
int dis
={0};
void dfs(int u){
for(int i=1;i<=14;i++){
p[u][i]=p[p[u][i-1]][i-1];
}
for(int i=first[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(p[u][0]==v)
continue;
p[v][0]=u;
dep[v]=dep[u]+1;
dis[v]=edge[i].w;
dfs(v);
}
}
int LCA(int x,int y){
int i,j;
if(dep[x]<dep[y])
swap(x,y);
for(i=0;(1<<i)<=dep[x];i++);
i--;
for(j=i;j>=0;j--){
if(dep[x]-(1<<j)>=dep[y])
x=p[x][j];
}
if(x==y)
return x;
if(x!=y){
for(j=i;j>=0;j--){
if(p[x][j]!=p[y][j]){
x=p[x][j];
y=p[y][j];
}
}
}
return p[x][0];
}
int getans(int x,int y){
int len=LCA(x,y);
int a=-0x7fffffff;
int b=-0x7fffffff;
for(int i=x;i!=len;i=p[i][0]){
a=max(a,dis[i]);
}
for(int i=y;i!=len;i=p[i][0]){
b=max(b,dis[i]);
}
return max(a,b);
}
int main(){
read(n);
read(m);
for(int i=1;i<=n;i++){
char ch[10];
scanf("%s",ch);
string s(ch);
// cin>>s;
name_cnt++;
name[s]=name_cnt;
}
for(int i=1;i<=m;i++){
char sa[10];
char sb[10];
scanf("%s",sa);
string a(sa);
scanf("%s",sb);
string b(sb);
int w;
// cin>>a;
// cin>>b;
read(w);
add(name[a],name[b],w);
add(name[b],name[a],w);
// cout<<name[s];
}
int q=0;
kruskal();
for(int i=1;i<=n;i++){
if(getfa(i)==i){
p[i][0]=i;
dfs(i);
}
}
read(q);
for(int i=1;i<=q;++i){
char sa[10];
char sb[10];
scanf("%s",sa);
string a(sa);
scanf("%s",sb);
string b(sb);
int ans=0;
ans=getans(name[a],name[b]);
printf("%d\n",ans);
}
}



万恶之源。
可以追溯到的最早的这种题。
但还就是MST完了LCA。
这个是这种题的绝对标准写法。#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define N (long long)3e5+10
#define INF (long long)1e18
inline void read(long long &x){
x=0;
long long 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;
}
struct Front_star{
long long u,v,w,nxt;
}e[N*2],edge[N*4];
long long n,m,q;
long long list_incoming
={0};
long long trade_sum
={0};
long long cnt=0;
void add(long long u,long long v,long long w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
}
long long ecnt=0;
long long first
={0};
void insert(long long u,long long v,long long w){
ecnt++;
edge[ecnt].u=u;
edge[ecnt].v=v;
edge[ecnt].w=w;
edge[ecnt].nxt=first[u];
first[u]=ecnt;
}
bool cmp(Front_star a,Front_star b){
return a.w>b.w;
}
// KRUSKAL
long long fa
={0};
inline long long getfa(long long x){
if(fa[x]==x){
return x;
}
else{
return fa[x]=getfa(fa[x]);
}
}
inline long long link(long long x,long long y){
long long dx=getfa(x);
long long dy=getfa(y);
fa[dx]=dy;
}
void kruskal(){
long long all=0;
for(long long i=1;i<=cnt;i++){
long long u=e[i].u;
long long v=e[i].v;
// cout<<"u= "<<u<<" v= "<<v<<endl;
if(getfa(u)!=getfa(v)){
all++;
link(u,v);
// cout<<u<<" "<<v<<" "<<e[i].w<<endl;
// cout<<e[i].w<<endl;
insert(u,v,e[i].w);
insert(v,u,e[i].w);
if(all==n-1)
break;
}
}
}
// LCA
long long f
[35]={0};
long long st
[35]={0};
long long dep
={0};
void dfs(long long u,long long fa){
// cout<<u<<" "<<fa<<endl;
for(long long i=1;(1<<i)<=dep[u];i++){
f[u][i]=f[f[u][i-1]][i-1];
st[u][i]=min(st[f[u][i-1]][i-1],st[u][i-1]);
}
for(long long i=first[u];i;i=edge[i].nxt){
long long v=edge[i].v;
long long w=edge[i].w;
if(v==fa)
continue;
dep[v]=dep[u]+1;
f[v][0]=u;
st[v][0]=w;
dfs(v,u);
}
}
long long lca(long long x,long long y){
long long ans=0;
if(dep[x]<dep[y]){
swap(x,y);
}
ans=INF+10;
long long t=dep[x]-dep[y];
for(long long i=0;(1<<i)<=t;i++){
if(t&(1<<i)){
ans=min(ans,st[x][i]);
x=f[x][i];
}
}
// cout<<"x= "<<x<<" "<<y<<endl;
if(x==y){
return ans;
}

for(long long i=20;i>=0;i--){
if(f[x][i]!=f[y][i]){
ans=min(ans,min(st[x][i],st[y][i]));
x=f[x][i];
y=f[y][i];
}
}
ans=min(ans,min(st[x][0],st[y][0]));
return ans;
}
int main(){
read(n);
read(m);
read(q);
for(long long i=1;i<=n;i++){
read(list_incoming[i]);
}
for(long long i=1;i<=n;i++){
read(trade_sum[i]);
}
for(long long i=1;i<=m;i++){
long long u,v,w;
read(u);
read(v);
read(w);
add(u,v,w);
}
// cout<<"hello wolrd"<<endl;
if(q){
long long u;
read(u);
for(long long i=2;i<=q;i++){
long long v;
read(v);
add(u,v,INF);
}
}
sort(e+1,e+1+cnt,cmp);
for(long long i=1;i<=n;i++){
fa[i]=i;
}
kruskal();
// f[1][0]=1;
// dep[1]=0;
dfs(list_incoming[1],0);
long long nowhaving=0;
if(trade_sum[list_incoming[1]]<0){
cout<<0<<endl;
// return 0;
}
else{
nowhaving=trade_sum[list_incoming[1]];
}
// for(long long i=1;i<=n;i++){
// for(long long j=0;j<=2;j++){
// cout<<st[i][j]<<" ";
// }
// cout<<endl;
// }
// cout<<lca(1,3);
for(long long i=1;i<n;i++){
long long u=list_incoming[i];
long long v=list_incoming[i+1];
long long LCA=lca(u,v);
// cout<<"LCA= "<<LCA<<" "<<u<<" "<<v<<endl;
nowhaving=min(nowhaving,LCA);
if(trade_sum[v]>0){
nowhaving+=trade_sum[v];
}
else{
printf("%lld\n",min(nowhaving,-trade_sum[v]));
nowhaving=max((long long)0,nowhaving+trade_sum[v]);
}
}
return 0;
}好了,做了基本一样的五个题,这类问题也算出师了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: