【線段樹】Count Color

Description
Chosen Problem Solving and Program design as an optional course, you are required to solve all
kinds of problems. Here, we get a new problem.

There is a very long board with length L centimeter, L is a positive integer, so we can evenly
divide the board into L segments, and they are labeled by 1, 2, ... L from left to right, each
is 1 centimeter long. Now we have to color the board - one segment with only one color. We can
do following two operations on the board:

1. "C A B C" Color the board from segment A to segment B with color C.
2. "P A B" Output the number of different colors painted between segment A and segment B (including).

In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you
may assume that the total number of different colors T is very small. To make it simple, we express
the names of colors as color 1, color 2, ... color T. At the beginning, the board was painted in
color 1. Now the rest of problem is left to your.

Input
First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000).
Here O denotes the number of operations. Following O lines, each contains "C A B C" or "P A B"
(here A, B, C are integers, and A may be larger than B) as an operation defined previously.

Output
Ouput results of the output operation in order, each line contains a number.

Sample Input

2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2

Sample Output

2
1

一道線段樹的入門題,詳見Mayor's Posters

Accode:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>

using std::bitset;

const char fi[] = "poj2777.in";
const char fo[] = "poj2777.out";
const int maxN = 100010;
const int maxC = 40;
const int MAX = 0x3fffff00;
const int MIN = -MAX;

struct SegTree{int L, R, lc, rc, col; };
SegTree tree[maxN << 2];
bitset <maxC> marked;
int n, m, tot, c;

  void init_file()
  {
    freopen(fi, "r", stdin);
    freopen(fo, "w", stdout);
  }
  
  void Build(int L, int R)
  {
    int Now = ++tot;
    tree[Now].L = L;
    tree[Now].R = R;
    tree[Now].col = 1; //最開始時顏色為1!
    int Mid = (L + R) >> 1;
    if (L < R)
    {
      tree[Now].lc = tot + 1;
      Build(L, Mid);
      tree[Now].rc = tot + 1;
      Build(Mid + 1, R);
    }
  }
  
  void insert(int Now, int L, int R, int col)
  {
    if (L <= tree[Now].L && R >= tree[Now].R)
      {tree[Now].col = col; return; }
    if (tree[Now].col > -1)
    {
      tree[tree[Now].lc].col =
        tree[tree[Now].rc].col =
        tree[Now].col;
      tree[Now].col = -1;
    }
    int Mid = (tree[Now].L + tree[Now].R) >> 1;
    if (L <= Mid) insert(tree[Now].lc, L, R, col);
    if (Mid < R) insert(tree[Now].rc, L, R, col);
  }
  
  void count(int Now, int L, int R)
  {
    if (tree[Now].col > -1)
      {marked.set(tree[Now].col); return; }
    int Mid = (tree[Now].L + tree[Now].R) >> 1;
    if (L <= Mid) count(tree[Now].lc, L, R);
    if (Mid < R) count(tree[Now].rc, L, R);
  }
  
  void work()
  {
    scanf("%d%d%d", &n, &c, &m);
    tot = 0;
    Build(1, n);
    for (; m; --m)
    {
      int x, y, z;
      switch (getchar(), getchar())
      {
        case 'P' :
        {
          scanf("%d%d", &x, &y);
          if (x > y) std::swap(x, y);
          marked.reset();
          count(1, x, y);
          int cnt = 0;
          for (int i = 1; i < c + 1; ++i)
            if (marked.test(i)) ++cnt;
          printf("%d\n", cnt);
          break;
        }
        case 'C' :
        {
          scanf("%d%d%d", &x, &y, &z);
          if (x > y) std::swap(x, y);
          insert(1, x, y, z);
          break;
        }
      }
    }
  }
  
int main()
{
  init_file();
  work();
  exit(0);
}


using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.Colors; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; namespace ScaffoldPlugin { public class ScaffoldCommands { // 配置参数 private static readonly double[] BarLengths = { 300, 600, 900, 1200, 1500, 1800 }; private static readonly string BlockDirectory = Path.Combine( Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), “ScaffoldBlocks”); // 容差参数 private const double ToleranceValue = 0.1; // 几何计算容差 private const double SpacingTolerance = 150.0; // 横杆长度匹配容差 private const double MinAxisLength = 100.0; // 最小轴网线长度 private const double MinDistanceForBar = 50.0; // 最小横杆间距 private const double MaxGapFactor = 1.2; // 最大间隙因子 // 块名称定义 private const string PoleBlockName = "ScaffoldPole立杆"; private const string BarPrefix = "ScaffoldPole横杆"; // 图层定义 private const string PoleLayer = "盘扣-立杆"; private const string BarLayer = "盘扣-横杆"; private const string AxisLayer = "盘扣轴网"; private const string DebugLayer = "盘扣-调试"; // 调试用图层 // 主命令:布置脚手架 [CommandMethod("BuildPlatform", "BP", CommandFlags.Modal)] public void BuildPlatform() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; try { // 检查块目录 if (!Directory.Exists(BlockDirectory)) { Directory.CreateDirectory(BlockDirectory); ShowErrorDialog($"块目录已创建: {BlockDirectory}\n请添加块文件后重新运行命令"); return; } // 创建所需图层 CreateLayerIfNotExists(db, PoleLayer, 7); // 红色 CreateLayerIfNotExists(db, BarLayer, 1); // 红色 CreateLayerIfNotExists(db, AxisLayer, 3); // 绿色 CreateLayerIfNotExists(db, DebugLayer, 2); // 黄色调试层 // 选择轴网线 var axisLineIds = SelectAxisLines(ed); if (axisLineIds == null || axisLineIds.Count == 0) { ShowErrorDialog("未选择轴网线或操作已取消!"); return; } // 获取轴网线对象 List<Line> axisLines = GetAxisLinesFromIds(db, axisLineIds); if (axisLines.Count == 0) { ShowErrorDialog("未找到有效轴网线!"); return; } // 计算有效交点(只在线段延伸相交处) ed.WriteMessage("\n正在计算有效交点..."); List<Point3d> validPoints = GetValidIntersectionPoints(axisLines); if (validPoints.Count == 0) { ShowErrorDialog("未找到有效交点!"); return; } ed.WriteMessage($"\n找到 {validPoints.Count} 个有效交点"); // 加载块定义 ed.WriteMessage("\n正在加载块定义..."); if (!LoadBlockDefinitions(db, ed)) return; // 理现有脚手架 ed.WriteMessage("\n开始理重叠区域的现有脚手架..."); CleanOverlappingScaffold(db, validPoints, ed); // 布置立杆(只在有效交点) ed.WriteMessage("\n开始布置立杆..."); int poleCount = PlacePoles(db, validPoints); ed.WriteMessage($"\n已布置 {poleCount} 根立杆"); // 布置横杆(只在连续线段) ed.WriteMessage("\n开始布置横杆..."); int barCount = PlaceBars(db, validPoints, axisLines, ed); ed.WriteMessage($"\n已布置 {barCount} 根横杆"); // 结果反馈 if (poleCount == 0 && barCount == 0) { ShowErrorDialog("脚手架布置失败,未布置任何构件!"); } else { Application.ShowAlertDialog($"成功布置 {poleCount}根立杆和{barCount}根横杆!"); } } catch (System.Exception ex) { ShowErrorDialog($"发生错误: {ex.Message}\n详细请查看命令行日志"); ed.WriteMessage($"\n错误: {ex.Message}\n{ex.StackTrace}"); } } // 选择轴网线 private List<ObjectId> SelectAxisLines(Editor ed) { var lineIds = new List<ObjectId>(); var filter = new SelectionFilter(new[] { new TypedValue(0, "LINE"), new TypedValue(8, AxisLayer) }); var opts = new PromptSelectionOptions { MessageForAdding = "\n选择盘扣轴网线 (按Enter结束选择): ", MessageForRemoval = "\n移除不需要的轴网线: ", AllowDuplicates = false, RejectObjectsOnLockedLayers = true }; PromptSelectionResult selection = ed.GetSelection(opts, filter); if (selection.Status != PromptStatus.OK) { ed.WriteMessage("\n未选择任何轴网线或选择已取消"); return lineIds; } using (var trans = ed.Document.TransactionManager.StartTransaction()) { foreach (ObjectId id in selection.Value.GetObjectIds()) { if (id.ObjectClass.DxfName == "LINE") { Entity entity = trans.GetObject(id, OpenMode.ForRead) as Entity; if (entity != null && entity.Layer == AxisLayer) { if (entity is Line line && line.Length > MinAxisLength) { lineIds.Add(id); } } } } trans.Commit(); } ed.WriteMessage($"\n已选择 {lineIds.Count} 条有效轴网线"); return lineIds; } // 从ID获取轴网线对象 private List<Line> GetAxisLinesFromIds(Database db, List<ObjectId> lineIds) { List<Line> lines = new List<Line>(); using (Transaction tr = db.TransactionManager.StartTransaction()) { foreach (ObjectId id in lineIds) { Line line = tr.GetObject(id, OpenMode.ForRead) as Line; if (line != null && line.Length > MinAxisLength) { lines.Add(line.Clone() as Line); // 克隆以避免原始对象修改 } } tr.Commit(); } return lines; } // 计算有效交点 private List<Point3d> GetValidIntersectionPoints(List<Line> axisLines) { List<Point3d> validPoints = new List<Point3d>(); for (int i = 0; i < axisLines.Count; i++) { for (int j = i + 1; j < axisLines.Count; j++) { Line line1 = axisLines[i]; Line line2 = axisLines[j]; Point3dCollection intersections = new Point3dCollection(); line1.IntersectWith(line2, Intersect.ExtendBoth, intersections, IntPtr.Zero, IntPtr.Zero); foreach (Point3d pt in intersections) { if (IsValidIntersection(pt, line1, line2)) { validPoints.Add(pt); } } } } // 移除重复点 return validPoints.Distinct(new Point3dComparer(ToleranceValue)).ToList(); } // 点比较器(考虑容差) private class Point3dComparer : IEqualityComparer<Point3d> { private readonly double _tolerance; public Point3dComparer(double tolerance) { _tolerance = tolerance; } public bool Equals(Point3d p1, Point3d p2) { return p1.DistanceTo(p2) < _tolerance; } public int GetHashCode(Point3d p) { return p.X.GetHashCode() ^ p.Y.GetHashCode() ^ p.Z.GetHashCode(); } } // 检查是否为有效交点 private bool IsValidIntersection(Point3d pt, Line line1, Line line2) { return IsPointOnLineSegment(pt, line1, ToleranceValue) && IsPointOnLineSegment(pt, line2, ToleranceValue); } // 检查点是否在线段范围内 private bool IsPointOnLineSegment(Point3d pt, Line line, double tolerance) { Vector3d lineVec = line.EndPoint - line.StartPoint; Vector3d startToPt = pt - line.StartPoint; double lineLengthSquared = lineVec.DotProduct(lineVec); double dotProduct = lineVec.DotProduct(startToPt); return dotProduct >= -tolerance && dotProduct <= lineLengthSquared + tolerance; } // 加载块定义 private bool LoadBlockDefinitions(Database db, Editor ed) { try { using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; // 加载立杆块 string polePath = Path.Combine(BlockDirectory, $"{PoleBlockName}.dwg"); if (!File.Exists(polePath)) { ShowErrorDialog($"立杆块文件未找到: {polePath}"); return false; } if (!bt.Has(PoleBlockName)) { using (Database sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(polePath, FileOpenMode.OpenForReadAndAllShare, false, null); db.Insert(PoleBlockName, sourceDb, true); ed.WriteMessage($"\n已加载立杆块: {PoleBlockName}"); } } // 加载横杆块 foreach (double length in BarLengths) { string barName = $"{BarPrefix}{length}mm"; string barPath = Path.Combine(BlockDirectory, $"{barName}.dwg"); if (!bt.Has(barName)) { if (File.Exists(barPath)) { using (Database sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(barPath, FileOpenMode.OpenForReadAndAllShare, false, null); db.Insert(barName, sourceDb, true); } ed.WriteMessage($"\n已加载横杆块: {barName}"); } else { ed.WriteMessage($"\n警告:横杆块文件未找到: {barPath}"); } } } tr.Commit(); } return true; } catch (System.Exception ex) { ShowErrorDialog($"加载块定义失败: {ex.Message}"); return false; } } // 理现有脚手架 private void CleanOverlappingScaffold(Database db, List<Point3d> points, Editor ed) { if (points.Count == 0) return; // 计算包围盒 double minX = points.Min(p => p.X); double maxX = points.Max(p => p.X); double minY = points.Min(p => p.Y); double maxY = points.Max(p => p.Y); // 扩展边界 double padding = BarLengths.Max() * 1.5; Point3d minPt = new Point3d(minX - padding, minY - padding, 0); Point3d maxPt = new Point3d(maxX + padding, maxY + padding, 0); using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTableRecord btr = tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord; // 创建选择过滤器 TypedValue[] filterValues = { new TypedValue(0, "INSERT"), new TypedValue(8, $"{PoleLayer},{BarLayer}") }; SelectionFilter filter = new SelectionFilter(filterValues); // 创建选择区域 Point3dCollection pts = new Point3dCollection(); pts.Add(minPt); pts.Add(new Point3d(maxPt.X, minPt.Y, 0)); pts.Add(maxPt); pts.Add(new Point3d(minPt.X, maxPt.Y, 0)); // 选择区域内的块 PromptSelectionResult psr = ed.Document.Editor.SelectCrossingPolygon(pts, filter); if (psr.Status == PromptStatus.OK) { int count = 0; foreach (ObjectId id in psr.Value.GetObjectIds()) { Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity; if (ent != null) { ent.Erase(); count++; } } ed.WriteMessage($"\n已理 {count} 个现有脚手架构件"); } tr.Commit(); } } // 布置立杆 private int PlacePoles(Database db, List<Point3d> points) { int count = 0; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; BlockTableRecord btr = tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord; if (!bt.Has(PoleBlockName)) { Application.ShowAlertDialog($"错误:立杆块 {PoleBlockName} 未加载!"); return 0; } ObjectId poleBlockId = bt[PoleBlockName]; foreach (Point3d pt in points) { if (double.IsNaN(pt.X) || double.IsNaN(pt.Y)) continue; BlockReference br = new BlockReference(pt, poleBlockId); br.Layer = PoleLayer; btr.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); count++; } tr.Commit(); } return count; } // 布置横杆 private int PlaceBars(Database db, List<Point3d> validPoints, List<Line> axisLines, Editor ed) { int count = 0; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; BlockTableRecord btr = tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord; // 创建点空间索引 Point3dTree pointTree = new Point3dTree(validPoints, ToleranceValue * 10); // 处理所有轴网线 foreach (Line line in axisLines) { // 找到线上所有有效交点 List<Point3d> linePoints = pointTree.GetPointsOnLine(line); if (linePoints.Count < 2) { continue; } // 按沿线的距离排序点 linePoints = linePoints.OrderBy(p => p.DistanceTo(line.StartPoint)).ToList(); // 将点分组为连续段 List<List<Point3d>> segments = GroupPointsIntoSegments(linePoints, line, ed); // 在每个连续段上布置横杆 foreach (var segment in segments) { if (segment.Count < 2) continue; for (int i = 0; i < segment.Count - 1; i++) { Point3d start = segment[i]; Point3d end = segment[i + 1]; double distance = start.DistanceTo(end); if (distance < MinDistanceForBar) continue; // 查找最匹配的标准长度 double bestLength = FindBestBarLength(distance); if (bestLength < 0) continue; // 计算中点 Point3d midPoint = new Point3d( (start.X + end.X) / 2, (start.Y + end.Y) / 2, (start.Z + end.Z) / 2); // 计算旋转角度 Vector3d direction = end - start; double angle = direction.GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis); // 处理角度象限问题 if (direction.Y < 0) angle = Math.PI * 2 - angle; // 生成块名 string blockName = $"{BarPrefix}{bestLength}mm"; if (!bt.Has(blockName)) { continue; } // 插入横杆 BlockReference br = new BlockReference(midPoint, bt[blockName]); br.Layer = BarLayer; br.Rotation = angle; btr.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); count++; } } } tr.Commit(); } return count; } // 查找最佳横杆长度 private double FindBestBarLength(double distance) { double bestLength = -1; double minDiff = double.MaxValue; foreach (double len in BarLengths) { double diff = Math.Abs(len - distance); if (diff < minDiff && diff <= SpacingTolerance) { minDiff = diff; bestLength = len; } } return bestLength; } // 将点分组为连续段 private List<List<Point3d>> GroupPointsIntoSegments(List<Point3d> points, Line line, Editor ed) { List<List<Point3d>> segments = new List<List<Point3d>>(); if (points.Count < 2) return segments; List<Point3d> currentSegment = new List<Point3d> { points[0] }; double maxGap = BarLengths.Max() * MaxGapFactor; for (int i = 1; i < points.Count; i++) { double distance = points[i - 1].DistanceTo(points[i]); if (distance > maxGap) { if (currentSegment.Count > 1) { segments.Add(currentSegment); } currentSegment = new List<Point3d> { points[i] }; } else { currentSegment.Add(points[i]); } } if (currentSegment.Count > 1) { segments.Add(currentSegment); } return segments; } // 创建图层 private void CreateLayerIfNotExists(Database db, string layerName, short colorIndex) { using (Transaction tr = db.TransactionManager.StartTransaction()) { LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable; if (!lt.Has(layerName)) { lt.UpgradeOpen(); LayerTableRecord ltr = new LayerTableRecord { Name = layerName, Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex), IsPlottable = true }; lt.Add(ltr); tr.AddNewlyCreatedDBObject(ltr, true); } tr.Commit(); } } // 显示错误对话框 private void ShowErrorDialog(string message) { Application.ShowAlertDialog(message); } } // 空间索引树 public class Point3dTree { private readonly List<Point3d> points; private readonly double tolerance; public Point3dTree(List<Point3d> points, double tolerance) { this.points = points; this.tolerance = tolerance; } public List<Point3d> GetPointsOnLine(Line line) { List<Point3d> result = new List<Point3d>(); // 计算线段包围盒 Point3d min = new Point3d( Math.Min(line.StartPoint.X, line.EndPoint.X) - tolerance, Math.Min(line.StartPoint.Y, line.EndPoint.Y) - tolerance, 0); Point3d max = new Point3d( Math.Max(line.StartPoint.X, line.EndPoint.X) + tolerance, Math.Max(line.StartPoint.Y, line.EndPoint.Y) + tolerance, 0); // 快速筛选候选点 foreach (Point3d pt in points) { if (pt.X >= min.X && pt.X <= max.X && pt.Y >= min.Y && pt.Y <= max.Y) { if (IsPointOnLineSegment(pt, line, tolerance)) { result.Add(pt); } } } return result; } // 检查点是否在线段范围内 private bool IsPointOnLineSegment(Point3d pt, Line line, double tolerance) { Vector3d lineVec = line.EndPoint - line.StartPoint; Vector3d startToPt = pt - line.StartPoint; double lineLengthSquared = lineVec.DotProduct(lineVec); double dotProduct = lineVec.DotProduct(startToPt); return dotProduct >= -tolerance && dotProduct <= lineLengthSquared + tolerance; } } } 网格斜线段的杆件布置不在斜线上 根据问题重新编写完整代码
最新发布
07-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值