二期鸡熏

8/12:

困。


8/13:

CSP-S 模拟 10


8/14:

S11


8/15:

% 你赛万元神去了,没时间写。


8/16:

% 你赛万元神去了,没时间写。


8/17:

% 你赛万元神去了,没时间写。


8/18:

搜索专题。

[NOIP2015 提高组] 斗地主 加强版 题解 BFS+DFS。

点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
 
inline int read()
{
    int x = 0, c = getchar(), f = 0;
    for (; c > '9' || c < '0'; f = c == '-', c = getchar())
        ;
    for (; c >= '0' && c <= '9'; c = getchar())
        x = (x << 1) + (x << 3) + (c ^ 48);
    return f ? -x : x;
}
 
unordered_map<ll, int> mp;
// mp[s] :  所有出过的牌的状态为 s 时,达成这个状态的最小次数。
int a[30]; // 排集
int n;
 
const ll ksm[15] = {1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, 6103515625};
// 5 进制状压
// 每一位存
 
int t[16] = {};
// 存每个点数出现了多少张牌
int st[30] = {}, tail = 0;
// 存手里还剩的牌的点数
 
int ans = 0, ans_cnt = 0;
// ans: 最小次数 ; ans_cnt:最小次数由哪个 cnt 被更新过来
 
struct Node
{
    int cnt;  // 现在打了多少次牌
    ll use;   // use:所有出过的牌的状态
    ll unuse; // unuse:所有没出的牌的状态
};
queue<Node> q; // BFS
 
// 更新答案
inline void get(const int &cnt, ll use, ll unuse)
{
    if (mp.count(use))
        return;                                       // 广搜一定是更优的状态先被搜到,所以之前搜到过则直接返回
    mp[use] = mp[use] == 0 ? cnt : min(cnt, mp[use]); // 更新打出牌状态为 use 的最小次数
    if (mp.count(unuse))                              // 如果
        ans = (ans == 0 ? cnt + mp[unuse] : min(ans, cnt + mp[unuse])), ans_cnt = cnt;
    else
        q.push({cnt, use, unuse});
}
 
/*
    一共打了 cnt 次,
    现在要选择打或不打 st[pos] 这张牌,
    到现在出的牌的状态为 use,没出过的牌的状态为 unuse,
    一共打了
     cnt1 个单,
     cnt2 个对
     cnt3 个三
     cnt4 个四
    ,
    上一个打出的牌是 last,若没有则为 -114514,
    pd 记录可否构成顺子
*/
 
void dfs(const int &cnt, int pos, ll use, ll unuse, int cnt1, int cnt2, int cnt3, int cnt4, int last, bool pd)
{
    if (ans && cnt != ans_cnt)
        return; // 非最优,返回
    if (pos > tail)
        return; // 没牌返回
 
    int num = st[pos];
    int c = t[num];
    if (num == 0)
    {
        get(cnt, use + 1, unuse - 1); // 0
        if (c == 2)                   // 0+0
            get(cnt, use + 2, unuse - 2);
 
        dfs(cnt, pos + 1, use + 1, unuse - 1, 1, cnt2, cnt3, cnt4, 0, 0); // 0 + ?
        dfs(cnt, pos + 1, use, unuse, cnt1, cnt2, cnt3, cnt4, last, pd);  // ?
        return;
    }
 
    if (c >= 4)
    {
        if (cnt1 == 2 && !cnt2 && !cnt3 && !cnt4) // 4+1+1
            get(cnt, use + ksm[num] * 4, unuse - ksm[num] * 4);
        if (!cnt1 && cnt2 == 2 && !cnt3 && !cnt4) // 4+2+2
            get(cnt, use + ksm[num] * 4, unuse - ksm[num] * 4);
        if (!cnt1 && !cnt2 && !cnt3 && !cnt4) // 4+0
            get(cnt, use + ksm[num] * 4, unuse - ksm[num] * 4);
 
        if (cnt1 == 1 && !cnt2 && !cnt3 && !cnt4) // 4+1+?
            dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2, cnt3, cnt4 + 1, num, 0);
        if (!cnt1 && cnt2 == 1 && !cnt3 && !cnt4) // 4+2+?
            dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2, cnt3, cnt4 + 1, num, 0);
        if (!cnt1 && !cnt2 && !cnt3 && !cnt4)
        {
            dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2, cnt3, cnt4 + 1, num, 0); // 4+?
            dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2 + 2, cnt3, cnt4, num, 0); // 2+2+?
        }
    }
 
    if (c >= 3)
    {
        if (cnt1 == 1 && !cnt2 && !cnt3 && !cnt4) // 3+1
            get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
        if (!cnt1 && cnt2 == 1 && !cnt3 && !cnt4) // 3+2
            get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
        if (!cnt1 && !cnt2 && !cnt3 && !cnt4) // 3
            get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
 
        if (!cnt1 && !cnt2 && !cnt3 && !cnt4 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 3+? 且不可能构成顺子(剪枝)
            dfs(cnt, pos + 1, use + ksm[num] * 3, unuse - ksm[num] * 3, cnt1, cnt2, cnt3 + 1, cnt4, num, 0);
    }
    if (c >= 2)
    {
        if (!cnt1 && cnt2 == 1 && !cnt3 && cnt4 == 1) // 2+4+2
            get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
        if (!cnt1 && !cnt2 && cnt3 == 1 && !cnt4) // 2+3
            get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
        if (!cnt1 && !cnt2 && !cnt3 && cnt4 == 1) // 1+1+4
            get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
        if (!cnt1 && !cnt2 && !cnt3 && !cnt4) // 2
            get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
 
        if (!cnt1 && !cnt2 && !cnt3 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 2+? // 2+4+? 且不可能构成顺子(剪枝)
            dfs(cnt, pos + 1, use + ksm[num] * 2, unuse - ksm[num] * 2, cnt1, cnt2 + 1, cnt3, cnt4, num, 0);
        if (!cnt1 && cnt2 == 1 && !cnt3 && !cnt4 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 2+2+?(4) 且不可能构成顺子(剪枝)
            dfs(cnt, pos + 1, use + ksm[num] * 2, unuse - ksm[num] * 2, cnt1, cnt2 + 1, cnt3, cnt4, num, 0);
    }
    if (c >= 1)
    {
        if (!cnt1 && !cnt2 && cnt3 == 1 && !cnt4)
            get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1); // 1+3
        if (cnt1 == 1 && !cnt2 && !cnt3 && cnt4 == 1)
            get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1); // 1+1+4
        if (!cnt1 && !cnt2 && !cnt3 && !cnt4)
            get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1); // 1+0
 
        if (!cnt1 && !cnt2 && !cnt3 && cnt4 <= 1 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 1+? // 1+4+? 且不可能构成顺子(剪枝)
            dfs(cnt, pos + 1, use + ksm[num] * 1, unuse - ksm[num] * 1, cnt1 + 1, cnt2, cnt3, cnt4, num, 0);
        if (cnt1 == 1 && !cnt2 && !cnt3 && !cnt4 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 1+1+?(4) 且不可能构成顺子(剪枝)
            dfs(cnt, pos + 1, use + ksm[num] * 1, unuse - ksm[num] * 1, cnt1 + 1, cnt2, cnt3, cnt4, num, 0);
    }
 
    if (num > 2 && pd) // 可能构成顺子
    {
        if ((last + 1 == num && last != 2) || last < 0) // 可能构成顺子
        {
            if (c >= 3 && !cnt1 && !cnt2 && !cnt4)
            {
                if (cnt3 >= 1) // 3+3+...
                    get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
 
                dfs(cnt, pos + 1, use + ksm[num] * 3, unuse - ksm[num] * 3, cnt1, cnt2, cnt3 + 1, cnt4, num, pd && (last + 1 == num || last < 0));
                // 尝试构成 3 顺
            }
            if (c >= 2 && !cnt1 && !cnt3 && !cnt4)
            {
                if (cnt2 >= 2) // 2+2+2+...
                    get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
 
                dfs(cnt, pos + 1, use + ksm[num] * 2, unuse - ksm[num] * 2, cnt1, cnt2 + 1, cnt3, cnt4, num, pd && (last + 1 == num || last < 0));
                // 尝试构成对顺
            }
            if (c >= 1 && !cnt2 && !cnt3 && !cnt4)
            {
                if (cnt1 >= 4) // 1+1+1+1+1+...
                    get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1);
 
                dfs(cnt, pos + 1, use + ksm[num] * 1, unuse - ksm[num] * 1, cnt1 + 1, cnt2, cnt3, cnt4, num, pd && (last + 1 == num || last < 0));
                // 尝试构成单顺
            }
        }
    }
 
    dfs(cnt, pos + 1, use, unuse, cnt1, cnt2, cnt3, cnt4, last, pd);
    // 不出这个点数的牌
}
 
void solve()
{
	// 注意清空 !!!!!
	ans = 0;
	ans_cnt = -1;
	while (q.size()) q.pop();
	mp.clear();
 
	for (int i = 1; i <= n; i++)
	{
		a[i] = read();
		if (a[i] == 1) a[i] += 13;
		read();
	}
	sort(a + 1, a + 1 + n);
 
	ll ansssss = 0;
	for (int i = 1; i <= n; i++) ansssss += ksm[a[i]];
 
	q.push({0, 0, ansssss});
	mp[0] = 0;
 
	if (n)
	{
		while (q.size())
		{
			int cnt = q.front().cnt + 1;
			ll use = q.front().use, unuse = q.front().unuse, x = unuse;
			if (ans && cnt != ans_cnt) break; // 搜到过且不可能有最优状态,则退出循环
            if (mp.count(unuse)) // 剪枝
    			ans = (ans == 0 ? cnt - 1 + mp[unuse] : min(ans, cnt - 1 + mp[unuse])), ans_cnt = cnt - 1;
 
			q.pop();
			tail = 0;
			memset(t, 0, sizeof(t));
			
			// 记录每个点数还需要出多少张牌
			for (int i = 0; i < 15; i++)
			{
				t[i] += x % 5;
				x /= 5;
				if (t[i]) st[++tail] = i;
			}
 
			dfs(cnt, 1, use, unuse, 0, 0, 0, 0, -114514, 1);
		}
	}
	cout << ans << "\n";
}
 
signed main()
{
	int T = read();
	n = read();
	while (T--) solve();
 
	return 0;
}

Anya and Cubes 折半搜索。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

int n,k,s;
int c[30],a[30],b[30];
int cnta,cntb;

unordered_map<int,int> mp[30];

int frac[30];

void dfs1(int pos,int cnt,int sum)
{
    // cout<<pos<<" "<<a[pos]<<"\n";
    // cout<<pos<<" "<<cnt<<" "<<sum<<"\n";
        // cout<<pos<<" "<<cnt<<" "<<k<<"  "<<sum<<" "<<s<<"\n";
    if(cnt>k) return;
    if(sum>s) return;
    if(pos>cnta)
    {
        // cout<<pos<<" "<<cnt<<" "<<sum<<"\n";
        mp[cnt][sum]++;
        // cout<<cnt<<" "<<sum<<"\n";
        return;
    }
    // cout<<"1\n";
    dfs1(pos+1,cnt,sum);
    // cout<<"2 "<<a[pos]<<" frac[a[pos]]="<<frac[a[pos]]<<"\n";
    if(a[pos]<=19)dfs1(pos+1,cnt+1,sum+frac[a[pos]]);
    // cout<<"3\n";
    dfs1(pos+1,cnt,sum+a[pos]);
}

int ans=0;

void dfs2(int pos,int cnt,int sum)
{
    if(cnt>k) return;
    if(sum>s) return;
    if(pos>cntb)
    {
        for(int i=k-cnt;i>=0;i--)
        if(mp[i].count(s-sum)) ans+=mp[i][s-sum];
        return;
    }
    dfs2(pos+1,cnt,sum);
    if(b[pos]<=18)dfs2(pos+1,cnt+1,sum+frac[b[pos]]);
    dfs2(pos+1,cnt,sum+b[pos]);
}

signed main()
{
    frac[0]=1;
    for(int i=1;i<=18;i++) frac[i]=frac[i-1]*i;
	// #ifndef ONLINE_JUDGE
	// freopen("a.in","r",stdin);
	// freopen("a.out","w",stdout);
	// #endif
	//mt19937_64 myrand(time(0));
    n=read();
    k=read();
    s=read();

    if(n==1)
    {

        int x=read();
        if(x<=18) ans+=frac[x]==s;
        ans+=x==s;
        cout<<ans;
        return 0;
    }

    for(int i=1;i<=n;i++)
    {
        c[i]=read();
        if(i<=(n>>1)) a[++cnta]=c[i];
        else b[++cntb]=c[i];
    }

    dfs1(1,0,0);
    dfs2(1,0,0);
    cout<<ans<<"\n";
	return 0;
}

[蓝桥杯 2023 省 A] 买瓜 还是折半搜索,注意要把瓜排序,要不然会 TLE。

点击查看代码
#include<bits/stdc++.h>
#define ll long long

using namespace std;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

int n,m;
// int a[1005];
unordered_map<signed,char> mp;
unordered_map<signed,bool> vis;
int a[105],b[105],cnta,cntb;
ll f2[105];
ll f[100];
int ans=0x3f3f3f3f;
inline int min(int x,int y) { return x<y?x:y; }

void dfs1(int pos,int cnt,int sum)
{
    // cout<<pos<<" sum="<<sum<<" "<<sum+f2[cnta]-f2[pos-1]+f[cntb]<<"<"<<m<<"\n";
    // if(cnt>k) return;
    if(sum>m) return;
    if(sum+f2[cnta]-f2[pos-1]+f[cntb]<m) return;
    // if(sum>m) return;
    if(pos>cnta)
    {
        if(!vis[sum]) vis[sum]=1,mp[sum]=cnt;
        // cout<<sum<<"\n";
        mp[sum]=min(mp[sum],cnt);
        return;
    }
    dfs1(pos+1,cnt,sum);
    dfs1(pos+1,cnt,sum+a[pos]);
    dfs1(pos+1,cnt+1,sum+(a[pos]>>1));
}

void dfs2(int pos,int cnt,int sum)
{
    if(sum>m) return;
    if(cnt>=ans) return;
    if(sum+f[cntb]-f[pos-1]+f2[cnta]<m) return;
    if(sum+f[cntb]-f[pos-1]==m)
    {
        ans=cnt;
        return;
    }
    // cout<<pos<<" "<<sum+f[cntb]-f[pos-1]+f[cnta]<<" "<<m<<"\n";
    // if(sum+(f2[cnta]>>1)>m) return;
    if(pos>cntb)
    {
        // cout<<sum<<"\n";
        if(vis.count(m-sum)) ans=min(ans,cnt+mp[m-sum]);
        return;
    }
    dfs2(pos+1,cnt,sum+b[pos]);
    dfs2(pos+1,cnt+1,sum+(b[pos]>>1));
    dfs2(pos+1,cnt,sum);
}

signed main()
{
	// #ifndef ONLINE_JUDGE
	// freopen("a.in","r",stdin);
	// freopen("a.out","w",stdout);
	// #endif
	//mt19937_64 myrand(time(0));
    n=read();
    m=read()<<1;
    int x[33]={};
    for(int i=1;i<=n;i++)
    {
        x[i]=read()<<1;    
    }
    std::sort(x+1,x+n+1,std::greater<ll>());
    // std::sort(b+1,b+cntb+1,std::greater<ll>());
    for(int i=1;i<=n;i++)
    {
        if(i<=(n>>1)) a[++cnta]=x[i];
        else b[++cntb]=x[i];
    }
    if(n==1)
    {
        // cout<<"nakna";
        if(b[1]==m) cout<<"0\n";
        else if((m<<1)==b[1]) cout<<"1\n";
        else cout<<"-1\n";
        return 0;
    }
    for(int i=1;i<=cntb;i++) f[i]=f[i-1]+b[i];
    for(int i=1;i<=cnta;i++) f2[i]=f2[i-1]+a[i];
    dfs1(1,0,0);
    // cout<<"\n\n";
    dfs2(1,0,0);
    if(ans>1000) ans=-1;
    cout<<ans;
	return 0;
}

8/19:

DP 专题。

P10599 BZOJ2164 采矿

先对原树进行树剖,然后和正常树剖一样建线段树,线段树每个节点设:

\(dp[p][k]\) 表示在点 \(p\) 所管辖的 dfn 序区间内任意节点任选 \(k\) 个人,所得到的最大价值。

\(g[p][k]\) 表示在点 \(p\) 所管辖的 dfn 序区间内只在 \(1\) 个节点选 \(k\) 个人,所得到的最大价值。

叶子结点初始化 \(dp[p]=g[p]=T[dfn[p]]\)

对于非叶子节点,显然我们有转移:

设左子树编号为 \(lp=(p<<1)\) ,右子树编号为 \(rp=(p<<1)|1\)

\[dp[p][i+j]=\max(dp[lp][i]+dp[rp][j]), i+j \le m \]

\[g[p][i]=max(g[lp][i],g[rp][i]) \]

修改操作直接修改即可。

查询时和修改一样,

a <- ans1 防止后效性, $$ans1[p][i+j]=\max(a[i]+dp[p][j]), i+j \le m$$

\[ans2[p][i]=max(ans2[p][i],g[p][i]) \]


8/20:

S14


8/21:


8/22:

机房断电,放假


8/23:

图论专题。

P2662 [WC2002] 牛场围栏

把所有木材长度预处理然后去重,跑同余最短路即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

int n,m;
int l[3005];
int cnt;
bool vis[10005];

priority_queue<pair<int,int> ,vector<pair<int,int> >,greater<pair<int,int> > > q;

int dis[3005];

signed main()
{
	n=read();
	m=read();
	for(int i=1;i<=n;i++)
	{
		int x=read();
		for(int j=0;j<=m&&x-j>0;j++)
		{
			if(vis[x-j]) continue;
			vis[x-j]=1;
		}
	}
	for(int i=1;i<=3000;i++) if(vis[i]) l[++cnt]=i;
	// for(int i=1;i<=cnt;i++) cout<<l[i]<<" ";
	// cout<<"\n";
    q.push(make_pair(0,0));
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));

    sort(l+1,l+1+cnt);
    dis[0]=0;
    const int mod=l[1];

    while(q.size())
    {
        int nw=q.top().second;
        q.pop();

        if(vis[nw]) continue;
        vis[nw]=1;
        // cout<<"nw="<<nw<<"\n";
        for(int i=2;i<=cnt;i++)
        {
            int to=(l[i]+nw);
            int dt=to/mod;
            to%=mod;
            if(dis[to]>dis[nw]+dt)
            {
                dis[to]=dis[nw]+dt; 
                q.push(make_pair(dis[to],to));
            }
            // cout<<"     -> to "<<to<<"\n";
        }
    }
    int ans=-1;
    for(int i=0;i<mod;i++)
    {
        // cout<<dis[i]<<" ";
        // cout<<"\n";
        if(dis[i]>0&&dis[i]<100000) ans=max(ans,i+(dis[i]-1)*mod);
    }
    cout<<ans<<"\n";

	// #ifndef ONLINE_JUDGE
	// freopen("a.in","r",stdin);
	// freopen("a.out","w",stdout);
	// #endif
	//mt19937_64 myrand(time(0));
	return 0;
}

P4211 [LNOI2014] LCA

妙妙题。

先将询问差分成 \([1,r] - [1,l-1]\) 两部分。

求前缀 deep[lca] 可以转化为:从前往后枚举点 \(i\),先根链 \(+1\) 加入 \(i\) 点,再算答案求根链和。

点击查看代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

const int N=1e5+5;
int n,m;
vector<int> E[N];
int fa[N];
int siz[N],dfn[N],top[N],son[N],dep[N],tot;
int sum[N<<2],lazy[N<<2];

#define pushdown()                          \
    {                                       \
        lazy[lp] += lazy[p];                \
        lazy[rp] += lazy[p];                \
        sum[lp] += lazy[p] * (mid - l + 1); \
        sum[rp] += lazy[p] * (r - mid);     \
        lazy[p] = 0;                        \
    }

void add(int l,int r,int sl,int sr,int k,int p)
{
	if(sl<=l&&r<=sr)
	{
		sum[p]+=k*(r-l+1);
		lazy[p]+=k;
		return;
	}
	int lp=(p<<1),rp=(p<<1)|1,mid=(l+r)>>1;
	if(lazy[p]) pushdown()
	
	if(sl<=mid) add(l,mid,sl,sr,k,lp);
	if(sr>mid) add(mid+1,r,sl,sr,k,rp);
	sum[p]=sum[lp]+sum[rp];
}

int query(int l,int r,int sl,int sr,int p)
{
    if(sl<=l&&r<=sr) return sum[p];
    
	int lp=(p<<1),rp=(p<<1)|1,mid=(l+r)>>1,ans=0;
	if(lazy[p]) pushdown()
	
	if(sl<=mid) ans=query(l,mid,sl,sr,lp);
	if(sr>mid) ans+=query(mid+1,r,sl,sr,rp);
	sum[p]=sum[lp]+sum[rp];
    return ans;
}

void dfs1(int p,int fa)
{
    siz[p]=1;
    dep[p]=dep[fa]+1;
    for(int to:E[p])
    {
        if(to==fa) continue;
        dfs1(to,p);
        // cerr<<p<<" "<<to<<"\n";
        siz[p]+=siz[to];
        // cerr<<son[p]<<" "<<siz[son[p]]<<" "<<siz[to]<<"\n";
        if(siz[to]>siz[son[p]]) son[p]=to;
    }
}

void dfs2(int p,int tp)
{
    dfn[p]=++tot;
    // add(1,n,tot,tot,0,1);
    top[p]=tp;
    if(son[p]) dfs2(son[p],tp);

    for(int to:E[p])
    if(!dfn[to]) dfs2(to,to);
}

int query(int u)
{
    // if(u==3) return 0;
    int ans=0;
    while(top[u]!=1) ans+=query(1,n,dfn[top[u]],dfn[u],1),u=fa[top[u]];//,cerr<<"u "<<u<<"\n";
    ans+=query(1,n,dfn[1],dfn[u],1);
    return ans;
}

void add(int u)
{
    while(top[u]!=1) add(1,n,dfn[top[u]],dfn[u],1,1),u=fa[top[u]];
    add(1,n,dfn[1],dfn[u],1,1);
}

struct Qu{
    int pos,op,z,id;
}ask[N<<1];
int cnt;
int ans[N];

bool cmp(Qu x,Qu y) { return x.pos<y.pos; }

signed main()
{
    n=read();
    m=read();
    for(int i=2;i<=n;i++)
    {
        fa[i]=read()+1;
        E[fa[i]].push_back(i);
    }
    dfs1(1,0);
    dfs2(1,1);
    // for(int i=1;i<=n;i++) cerr<<son[i]<<" ";
    // cout<<"\n";

    for(int i=1;i<=m;i++)
    {
        int l=read()+1,r=read()+1,z=read()+1;
        ask[++cnt]={l-1,-1,z,i};
        ask[++cnt]={r,1,z,i};
    }
    sort(ask+1,ask+1+cnt,cmp);
    // return 0;

    int nw=0;
    for(int i=1;i<=cnt;i++)
    {
        // cerr<<"i="<<i<<" ask[i].pos="<<ask[i].pos<<" nw="<<nw<<" z="<<ask[i].z<<"\n";
        while(nw<ask[i].pos)
        {
            // cerr<<"iubsdfbid";
            nw++;
            add(nw);
        }
        ans[ask[i].id]+=ask[i].op*query(ask[i].z);
    }
    for(int i=1;i<=m;i++) write(ans[i]%201314),putchar('\n');

	return 0;
}

8/24:

图论专题。


8/25:

LCT(LiChao Tree)

基于斜率的李超树代码
#include<stdio.h>
#include<cmath>
#include<algorithm>

using std::swap;
using std::abs;
using std::min;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

const int MAXN=40000;
int n;

struct ed{
	double y1,y2,k,mid;
	int id;
}nw,t[MAXN<<3];
int root[1<<20];
int tot;

const double eps=1e-9;

void add(int l,int r,int p)
{       
	int mid=(l+r)>>1,lp=(p<<1),rp=(p<<1)|1;
	nw.mid=(mid-l)*nw.k+nw.y1;
    if(nw.mid>t[p].mid) swap(t[p],nw);

	if(l==r)
	{
		if(abs(t[p].mid-nw.mid)<eps) t[p].id=min(t[p].id,nw.id==0?0x3f3f3f3f:nw.id);
		return;
	}
    if(t[p].y1>nw.y1&&t[p].y2>nw.y2) return;
    if(abs(t[p].k-nw.k)<eps&&abs(t[p].mid-nw.mid)<eps)
    {
        t[p].id=min(t[p].id,nw.id==0?0x3f3f3f3f:nw.id);
        return;
    }
	if(abs(nw.mid-t[p].mid)<eps&&nw.k>t[p].k) swap(nw,t[p]);

	if(t[p].k>nw.k) nw.y2=nw.y1+(mid-l)*nw.k,add(l,mid,lp); 
	else nw.y1=nw.y1+(mid-l+1)*nw.k,add(mid+1,r,rp);
}           

void add(int l,int r,int sl,int sr,int y0,double k,int id,int p)
{
    if(sl<=l&&r<=sr)
    {
		double y1=(l-sl)*k+y0,y2=(r-sl)*k+y0;
		nw={y1,y2,k,0,id};
        add(l,r,p);
        return;
    }
    int mid=(l+r)>>1,lp=(p<<1),rp=(p<<1)|1;
    if(sl<=mid) add(l,mid,sl,sr,y0,k,id,lp);
    if(sr>mid) add(mid+1,r,sl,sr,y0,k,id,rp);
}

void query(double &ans,int &ans_id,int l,int r,int x,int p)
{
	int mid=(l+r)>>1;
	double nw=t[p].y1+(x-l)*t[p].k;	

	if(t[p].id)
	{
		if(nw>ans) ans=nw,ans_id=t[p].id;
		else if(abs(nw-ans)<=eps) ans_id=min(ans_id,t[p].id);		
	}
	if(l==r) return;
	if(x<=mid) query(ans,ans_id,l,mid,x,p<<1);
	if(x>mid) query(ans,ans_id,mid+1,r,x,(p<<1)|1);
}

signed main()
{
	n=read();
	int lastans=0,cnt=0;
	while(n--)
	{
		int op=read();
		if(op==0)
		{
			int x=read();
			double ans=0;
			x=(x+lastans-1+39989)%39989+1;
			lastans=0x3f3f3f3f;

			query(ans,lastans,1,MAXN,x,1);
			if(lastans==0x3f3f3f3f)lastans=0;
			write(lastans),putchar('\n');
		}
		else
		{
			int x0=read(),y0=read(),x1=read(),y1=read();

			x0+=lastans-1;x0%=39989;x0++;
			x1+=lastans-1;x1%=39989;x1++;
			y0+=lastans-1;y0%=1000000000;y0++;
			y1+=lastans-1;y1%=1000000000;y1++;

			if(x0>x1) swap(x0,x1),swap(y0,y1);
			double k=y1-y0;
			if(x1==x0) y0=y1,k=1e9;
			else k/=x1-x0;

			add(1,MAXN,x0,x1,y0,k,++cnt,1);
		}
	}
	return 0;
}

随贪:

https://www.luogu.com.cn/discuss/1142478


8/26:


8/27:


8/28:


posted @ 2025-08-12 21:08  Wy_x  阅读(50)  评论(5)    收藏  举报