传送门
文章目录
- 题意:
- 思路:
题意:
构造一个图,使其从111到nnn的路径的长度与[L,R][L,R][L,R]中某个值一一对应,不能有两条路径长度一样,且每个值都必须出现一次,每两个点之间只能连一条边。
n≤32n\le32n≤32,ai,bi≤na_i,b_i\le nai,bi≤n,1≤ci≤1e61\le c_i\le 1e61≤ci≤1e6。
思路:
看到n≤32n\le 32n≤32,不难想到二进制拆分,我们分情况来讨论。
(1)L=1,R=2k(1)\ \ L=1,R=2^k(1) L=1,R=2k
对于这种情况,我们需要拿出来k+2k+2k+2个点,从111向[2,k+2][2,k+2][2,k+2]的点连边权为111的边,让后对于后面的每一个位置iii,都向后连边权为2i−22^{i-2}2i−2的边,这样就可以构造出[1,2k][1,2^k][1,2k]内的边权了。
(2)L=1,R>1(2)\ \ L=1,R>1(2) L=1,R>1
对于这种情况,我们依旧按照(1)(1)(1)的思路构造出[1,2k][1,2^k][1,2k]的边权,让后再新加一个点k+3k+3k+3,考虑用新的点来构造出来[2k+1,R][2^k+1,R][2k+1,R]的边权。
对于RRR,他的二进制形式大概是这样的100100100...100100100...100100100...,很明显,我们可以根据111来分段,因为我们已经构造出来了[1,2i][1,2^i][1,2i],即[1,1000..][1,1000..][1,1000..],假设RRR的从低位到高位的第iii位(从000开始)是111,那么我们只需要从i+2i+2i+2的位置向k+3k+3k+3连一个RRR将iii位及其之后的数都变成000的边权,但是这样会有点问题,就是因为构造的是[1,2i][1,2^i][1,2i],缺少000,那么连完之后也就缺少后面全000的边权。所以我们考虑将R−1R-1R−1之后建边,在新边的边权都+1+1+1即可。
(3)L>1,R>1(3)\ \ L>1,R>1(3) L>1,R>1
只需要在最后新加一个点,在原来的最后一个点向他连l−1l-1l−1的边即可,转化成情况(1)(1)(1)或(2)(2)(2)。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int l,r;
int tot;
struct Node
{int a,b,w;
}edge[N];void add(int a,int b,int c)
{edge[++tot]={a,b,c};
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cin>>l>>r;puts("YES");int rr=r-l+1;int k=0;while((1<<k)<rr) k++;if((1<<k)==r){int cnt=k+2;for(int i=2;i<=k+2;i++) add(1,i,1);for(int i=2;i<=k+2;i++)for(int j=i+1;j<=k+2;j++)add(i,j,1<<(i-2));if(l>1) add(cnt,cnt+1,l-1),cnt++;printf("%d %d\n",cnt,tot);for(int i=1;i<=tot;i++) printf("%d %d %d\n",edge[i].a,edge[i].b,edge[i].w);}else {k--;int cnt=k+3;for(int i=2;i<=k+2;i++) add(1,i,1);for(int i=2;i<=k+2;i++)for(int j=i+1;j<=k+2;j++)add(i,j,1<<(i-2));add(1,k+3,1);for(int i=0;i<=k;i++)if((rr-1)>>i&1)add(i+2,k+3,((rr-1)>>(i+1)<<(i+1))+1);if(l>1) add(cnt,cnt+1,l-1),cnt++;printf("%d %d\n",cnt,tot);for(int i=1;i<=tot;i++) printf("%d %d %d\n",edge[i].a,edge[i].b,edge[i].w);}return 0;
}
/**/