线段树合集 I

简介

基于个人对线段树的理解,线段树的核心思想就在于离散化和滞后性

hdu 1166 敌兵布阵(入门级)

hdu 1542 Atlantis

将线段离散化,自己一开始利用线段树将沿y坐标的矩阵归并可惜总是wa,最后借鉴了别人的方法

#include <cstdio>
#include <algorithm>
using namespace std;

const int MAXN = 5000;
double MM[MAXN];
double sum;
struct node 
{
    double len;
    int bz;
}data[MAXN<<2];

struct line
{
    double x1, x2, y;
    int typ;
    bool operator < (const line & a) const
    {
        if (y != a.y)    return y < a.y;
        return typ > a.typ;
    }
}mLine[MAXN*2];

#define ll (cnt<<1)
#define rr ((cnt<<1)|1)
#define lson l,m,ll
#define rson m,r,rr
#define mid m=(l+r)>>1

void build(int l, int r, int cnt)
{
    data[cnt].bz = 0;
    data[cnt].len = 0.0;
    if (l+1 == r) return;
    int mid;
    build(lson);
    build(rson);
}

void pushUP (int l, int r, int cnt )
{
    if (data[cnt].bz)
        data[cnt].len = MM[r] - MM[l];
    else
    {
        if (l+1 == r) data[cnt].len = 0.0;
        else
            data[cnt].len = data[ll].len + data[rr].len;
    }
}

void solve(int t, int x1, int x2, int l, int r, int cnt)
{
    if (x1 <= l && x2 >= r)
    {
        data[cnt].bz += t;
        pushUP(l, r, cnt);
        return;
    }
    if (l+1 == r) return;
    int mid;
    if (x1 < m) solve(t, x1, x2, lson);
    if (x2 > m) solve(t, x1, x2, rson);
    pushUP(l, r, cnt);
}
int n, m, d;
int mfind(double c)
{
    int p, q;
    p = 0;
    q = d - 1;
    while( p <= q )
    {
        int md=(p+q)/2;
        if(MM[md]==c)
            return md;
        if(MM[md]<c)
            p=md+1;
        else
            q=md-1;
    }
    return -1;
}
int main() 
{
    int cs = 0;
    while (scanf("%d", &n) != EOF && n)
    {
        m = 0;
        sum = 0.0;
        double x1, y1, x2, y2;
           for (int i = 0; i< n; ++i)
        {            
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            if ( (y2-y1)*(x2-x1) == 0.0) continue;
            line tp;
            tp.x1 = x1; tp.x2 = x2;
            tp.y = y1; tp.typ = 1;
            MM[m] = x1;
            mLine[m++] = tp;
            
            tp.y = y2; tp.typ = -1;
            MM[m] = x2;
            mLine[m++] = tp;
        }
        sort(mLine, mLine+m);
        sort(MM, MM+m);
        d = 1;
        for (int i = 1; i< m; ++i)
        {
            if (MM[i] != MM[d-1])
            {
                MM[d++] = MM[i];
            }
        }
        build(0, d-1, 1);
        for (int i = 0; i< m-1; ++i)
        {
            int a = mfind(mLine[i].x1);
            int b = mfind(mLine[i].x2);
            solve(mLine[i].typ, a, b, 0, d-1, 1);
            sum += data[1].len * (mLine[i+1].y - mLine[i].y);
        }
        printf("Test case #%d\n", ++cs);
        printf("Total explored area: %.2lf\n\n", sum);
    }
    return 0;
}


hdu 2795 Billboard

题目有个陷阱,实际上段数等于h和n的最小值就可以

#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <cmath>
using namespace std;
#ifdef __GNUC__
#define LL long long
#else
#define LL __int64
#endif

const int MAXN = 200005;
#define ll (cnt<<1)
#define rr ((cnt<<1)|1)
#define lson l,md,ll
#define rson md+1,r,rr
#define mid md=(l+r)>>1
int h, w, n; 
int mxNum[MAXN*3];
void build(int l, int r, int cnt)
{
	mxNum[cnt] = w;
	if (l == r) return;
	int mid;
	build(lson);
	build(rson);
}

int solve(int a, int l, int r, int cnt)
{
	if (l == r)
	{
		mxNum[cnt] -= a;
		return l;
	}
	int e;
	int mid;
	if (mxNum[ll] >= a)
	{
		e = solve(a, lson);
	}
	else
	{
		e = solve(a, rson);
	}
	mxNum[cnt] = max(mxNum[ll], mxNum[rr]);
	return e;
}
int main() 
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    while (scanf("%d%d%d", &h, &w, &n) != EOF)
    {
    	h = min(h, n);
    	build(1, h, 1);
    	while (n--)
    	{
	    	int a, b;
	    	scanf("%d", &a);
	    	if (a > mxNum[1]) b = -1;
	    	else
	    	{
	    		b = solve(a, 1, h, 1);
	    	}
	    	printf("%d\n", b);
	    }
    }
    return 0;
}


hdu 3308 LCIS

线段树合并,算是基础上的稍加变化

#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <cmath>
using namespace std;
// hdu 3308
#define ll (rot<<1)
#define rr (ll | 1)
#define mid mm = (l+r)>>1
#define lson l,mm,ll
#define rson mm+1,r,rr
const int MAXN = 100005<<2;
struct mNode
{
	int l, r;
	int lf, rt, md;
}node[MAXN];
int num[MAXN];
int n, m;
inline void solve(mNode *a, mNode *bl, mNode *br)
{
	a->md = max(bl->md, br->md);
	int mm = bl->r;
	if (num[mm] < num[1+mm])
	{
		int k = bl->rt + br->lf;
		a->md = max(a->md, k);
		if (bl->lf == (bl->r-bl->l+1))
		{
			a->lf = bl->lf + br->lf;
		}
		else
		{
			a->lf = bl->lf;
		}
		if (br->rt == (br->r-mm))
		{
			a->rt = bl->rt + br->rt;
		}
		else
		{
			a->rt = br->rt;
		}
	}	
	else
	{
		a->lf = bl->lf;
		a->rt = br->rt;
	}
}
void build(int l, int r, int rot)
{
	node[rot].l = l;
	node[rot].r = r;
	if (l == r)
	{
		node[rot].lf = node[rot].rt= node[rot].md = 1;
		return;
	}
	int mid;
	build(lson);
	build(rson);
	solve(node+rot, node+(ll), node+(rr));
}
void change(int a, int b, int l, int r, int rot)
{
	if (l == r)
	{
		num[l] = b;
		node[rot].lf = node[rot].rt= node[rot].md = 1;
		return;
	}
	int mid;
	if (a <= mm) change(a, b, lson);
	else change(a, b, rson);
	solve(node+rot, node+(ll), node+(rr));
}
mNode query(int x, int y, int l, int r, int rot)
{
	mNode res, a, b;
	if (x <= l && y >= r)
	{
		return node[rot];
	}
	int mid;
	if (y <= mm)
	{
		return query(x, y, lson);
	}
	if (x > mm)
	{
		return query(x, y, rson);
	}
	a = query(x, y, lson);
	b = query(x, y, rson);
	res.l = a.l; res.r = b.r;
	solve(&res, &a, &b);
	return res;
}
char c[5];
int main() 
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &n, &m);
		for(int i = 0; i< n; ++i)
		{
			int a;
			scanf("%d", num+i);
		}
		build(0, n-1, 1);
		while (m--)
		{
			int a, b;
			scanf("%s%d%d", c, &a, &b);
			if (c[0] == 'U')
			{
				change(a, b, 0, n-1, 1);
			}
			else
			{
				mNode res = query(a, b, 0, n-1, 1);
				printf("%d\n", res.md);
			}
		}
	}
    return 0;
}


hdu 4027 Can you answer these queries?

 

线段树应用,但题目的突破口是 2^63 最多被开方6次

#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <cmath>
using namespace std;
// hdu 4027
typedef __int64 LL;
#define ll (rot<<1)
#define rr (ll | 1)
#define mid mm = (l+r)>>1
#define lson l,mm,ll
#define rson mm+1,r,rr
const int MAXN = 100005<<2;
struct mNode
{
	LL all;
	int flg;
}data[MAXN];
LL num[MAXN];
void build(int l, int r, int rot)
{
	data[rot].flg = 0;
	if (l == r)
	{	
		data[rot].all = num[l];
		if (num[l] == 1) data[rot].flg = 1;
		return;
	}
	int mid;
	build(lson);
	build(rson);
	data[rot].all = data[ll].all + data[rr].all;
	data[rot].flg = data[ll].flg & data[rr].flg;
}
void add(int x, int y, int l, int r, int rot)
{
	if (data[rot].flg) return;
	if (l == r)
	{
		data[rot].all = (LL)sqrt(data[rot].all);
		if (data[rot].all == 1) data[rot].flg = 1;
		return;
	}	
	int mid;
	if (x <= mm) add(x, y, lson);
	if (y > mm) add(x, y, rson);
	data[rot].all = data[ll].all + data[rr].all;
	data[rot].flg = data[ll].flg & data[rr].flg;
}
LL query(int x, int y, int l, int r, int rot)
{
	LL sum = 0;
	if (x <= l && y >= r )
	{
		return data[rot].all;
	}
	int mid;
	if (x <= mm) sum += query(x, y, lson);
	if (y > mm) sum += query(x, y, rson);
	return sum;
}
int main() 
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
	int n, t = 0;
	while (scanf("%d", &n) != EOF)
	{
		printf("Case #%d:\n", ++t);
		for (int i = 1; i<= n; ++i)
		{
			scanf("%I64d", &num[i]);
		}
		build(1, n, 1);
		int k;
		scanf("%d", &k);
		while (k--)
		{
			int a, b, c, d, e;
			scanf("%d%d%d", &a, &d, &e);
			b = min(d, e);
			c = max(d, e);
			if (a == 0)
			{
				add(b, c, 1, n, 1);
			}
			else
			{
				printf("%I64d\n", query(b, c, 1, n, 1));
			}
		}
		puts("");
	}
    return 0;
}

hdu 3974 Assign the task

简单题
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
/* 
	acm.hdu.edu.cn/showproblem.php?pid=3974
*/
const int MAXN = 50005*2;
#define ll (root<<1)
#define rr (ll|1)
#define lson l,m,ll
#define rson m+1,r,rr
#define mid m=(l+r)>>1
int lf[MAXN], rt[MAXN], cnt;
struct Edge
{
	int v, next;
}edge[MAXN*2];
int head[MAXN], e, fa[MAXN];
int data[MAXN*2], sz[MAXN*2];
void m_init()
{
	memset(head, -1, sizeof head);
	memset(fa, -1, sizeof fa);
	e = cnt = 0;
}
void add(int u, int v)
{
	fa[v] = u;
	edge[e].v = v;
	edge[e].next = head[u];
	head[u] = e++;
}
void build(int l, int r, int root)
{
	data[root] = -1;
	sz[root] = 0;
	if (l == r) return;
	int mid;
	build(lson); build(rson);
}
void pushDown(int root)
{
	if (!sz[root]) return;
	sz[root] = 0;
	data[ll] = data[rr] = data[root];
	sz[ll] = sz[rr] = 1;
}
void change(int c, int x, int y, int l, int r, int root)
{
	if (x <= l && y >= r)
	{
		data[root] = c; sz[root] = 1;
		return;
	}
	pushDown(root);
	int mid;
	if (x <= m) change(c,x,y,lson);
	if (y > m) change(c,x,y,rson);
}
int query(int x, int l, int r, int root)
{
	if (l == r) return data[root];
	pushDown(root);
	int mid;
	if (x <= m) return query(x,lson);
	if (x > m) return query(x,rson);
}
void dfs(int u)
{
	lf[u] = cnt++;
	for (int i= head[u]; ~i; i = edge[i].next)
	{
		dfs(edge[i].v);
	}
	rt[u] = cnt-1;
}
char str[3];
int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int t, cs = 0;
	int n, m;
	scanf("%d", &t);
	while (t--)
	{
		printf("Case #%d:\n", ++cs);
		m_init();
		scanf("%d", &n);
		for (int i = 1; i< n; ++i)
		{
			int v, u;
			scanf("%d%d", &v, &u);
			add(u,v);
		}
		int k;
		for (int i = 1; i<= n; ++i)
		{
			if (fa[i] == -1)
			{
				k = i;
				break;
			}
		}
		dfs(k);
		build(0, cnt-1, 1);
		scanf("%d", &m);
		while (m--)
		{
			int a, b;
			scanf("%s", str);
			if (str[0] == 'C')
			{
				scanf("%d", &a);
				printf("%d\n", query(lf[a],0,cnt-1,1));
			}
			else
			{
				scanf("%d%d", &a, &b);
				change(b, lf[a], rt[a], 0, cnt-1, 1);
			}
		}
	}
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值